diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d0479b..f9b0404 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ## [Unreleased] +### Added — deltag.aarhus.dk Project +- Hearing detail page prototype for Aarhus Kommune's citizen participation platform +- Interactive mock with 784 simulated hearing responses, filtering, sorting, MitID login, submission form +- Variant switching between open and closed hearing states +- Statistics (SVG line chart, category breakdown), interactive map, glossary tooltips +- Editor content requirements document (redaktionelt indhold) + ### Changed - Migrated from MkDocs + Material theme to VitePress - Adopted ITK Dev brand colors (teal/cyan) replacing neutral black/grey palette diff --git a/docs/.vitepress/sidebar.mts b/docs/.vitepress/sidebar.mts index d56362e..ae640dd 100644 --- a/docs/.vitepress/sidebar.mts +++ b/docs/.vitepress/sidebar.mts @@ -37,11 +37,23 @@ const agenticOrchestration: DefaultTheme.SidebarItem[] = [ }, ] +const deltagAarhus: DefaultTheme.SidebarItem[] = [ + { + text: 'deltag.aarhus.dk', + items: [ + { text: 'Overview', link: '/projects/deltag-aarhus/' }, + { text: 'Redaktionelt indhold', link: '/projects/deltag-aarhus/editor-content-requirements' }, + { text: 'Interactive Mocks', link: '/projects/deltag-aarhus/mocks' }, + ], + }, +] + export function sidebar(): DefaultTheme.Sidebar { return { '/projects/climate-nudging/': climateNudging, '/projects/salary-negotiation/': salaryNegotiation, '/projects/agentic-orchestration/': agenticOrchestration, + '/projects/deltag-aarhus/': deltagAarhus, } } diff --git a/docs/index.md b/docs/index.md index d4bb0c1..8bcd234 100644 --- a/docs/index.md +++ b/docs/index.md @@ -18,4 +18,8 @@ features: details: Can we build a shared, open-source platform for mapping, automating, orchestrating, and measuring business processes? link: /projects/agentic-orchestration/ linkText: View project + - title: deltag.aarhus.dk + details: Prototype af en høringsdetalje-side til Aarhus Kommunes borgerdeltagelsesplatform — med 784 simulerede høringssvar, MitID-login og variantskift. + link: /projects/deltag-aarhus/ + linkText: View project --- diff --git a/docs/projects/deltag-aarhus/editor-content-requirements.md b/docs/projects/deltag-aarhus/editor-content-requirements.md new file mode 100644 index 0000000..f732cb6 --- /dev/null +++ b/docs/projects/deltag-aarhus/editor-content-requirements.md @@ -0,0 +1,156 @@ +# Redaktionelt indhold — Høringsdetalje side + +Oversigt over indhold som redaktører skal bidrage med per høring, samt hvad der kan genereres automatisk fra eksisterende data. + +## Oversigt + +| Sektion | Redaktør | Automatisk | Bemærkning | +|---------|:--------:|:----------:|------------| +| Hero-billede | X | | Billede skal uploades per høring | +| Afgørelsesbanner | X | delvist | Redaktør skriver tekst; dato kan trækkes fra dagsordensystem | +| Afgørelsesdialog | X | delvist | Redaktør skriver resumé; links til referat/video kan trækkes fra byrådets dagsordensystem | +| Overskrift og manchet | X | | Fritekst per høring | +| Metadata (svarfrist, type, ID) | | X | Findes i høringsdata | +| Tags/kategorier | X | | Redaktør vælger fra taksonomi | +| Brødtekst | X | | Fritekst med mulighed for ordforklaringer | +| Ordforklaringer (glossary) | X | delvist | Redaktør markerer termer; forklaringstekst kan trækkes fra central ordliste | +| Materialer | X | | Redaktør uploader filer og angiver navne | +| HTML-forhåndsvisning af materialer | | X | Kan genereres automatisk fra uploadet PDF | +| Svarfrist og slettedato | | X | Findes i høringsdata | +| Kontaktoplysninger | X | delvist | Redaktør vælger afdeling; kontaktdata kan trækkes fra kontaktregister | +| Høringssvar | | X | Indsendt af borgere via formularen | +| Høringssvar-kategorier | delvist | delvist | Kategori-taksonomi vedligeholdes af redaktør; tildeling kan evt. automatiseres med AI | +| Kommentarer | | X | Indsendt af borgere | +| Statistik — linjediagram | | X | Beregnes automatisk fra indkomne svar | +| Statistik — kategorifordeling | | X | Beregnes automatisk fra kategoriserede svar | +| Geografisk fordeling (kort) | | X | Beregnes fra afsenderadresse/postnummer | +| Info-boks (Mere viden) | X | | Redaktør vælger links fra vidensbase | +| Relaterede aktiviteter | X | delvist | Redaktør knytter relationer; billeder og metadata trækkes automatisk | +| Projekter CTA | | X | Global komponent — konfigureres én gang | +| Footer | | X | Global komponent | + +--- + +## Detaljer per sektion + +### 1. Hero-billede + +**Redaktøropgave:** Upload et billede der repræsenterer høringsområdet. + +- Anbefalet størrelse: 1600 x 500 px +- Alt-tekst skal udfyldes + +### 2. Afgørelsesbanner og -dialog + +**Redaktøropgave:** +- Kort bannerbesked (1 sætning) med mødedato og udfald +- Resumé af afgørelsen (2-3 afsnit) til afgørelsesdialogen + +**Automatisk:** +- Mødedato kan trækkes fra byrådets dagsordensystem +- Link til referat (PDF) og video kan trækkes automatisk, hvis byrådets system har en API +- Link til vedtaget lokalplan kan genereres fra dokumentsystemet + +**Redaktøren skal levere:** +- Link til hvidbog (behandling af høringssvar) — dette dokument produceres manuelt +- Eventuelle tilpasninger af resuméteksten + +### 3. Overskrift, manchet og brødtekst + +**Redaktøropgave:** Fritekst. Ingen automatisering mulig — dette er det primære redaktionelle indhold. + +### 4. Ordforklaringer (glossary) + +**Redaktøropgave:** Markere fagtermer i brødteksten der skal have en forklaring. + +**Automatisk:** +- Forklaringstekst og "læs mere"-link kan trækkes fra en **central ordliste/taksonomi** i CMS +- Systemet kan evt. automatisk foreslå termer der bør markeres (baseret på ordlisten) +- Kræver oprettelse og vedligeholdelse af en ordliste med fagtermer og forklaringer + +**Vedligeholdelse af ordliste:** +- Ordlisten bør forvaltes centralt (ikke per høring) +- Hver term: navn, kort forklaring (maks 2 sætninger), link til uddybende side +- Eksempler: omdannelsesområde, boligbebyggelse, kommuneplan, rammeområde, bebyggelsesprocent, LAR-løsning + +### 5. Materialer + +**Redaktøropgave:** +- Upload dokumenter (PDF, billeder) +- Angiv dokumentnavn +- Vælg om dokumentet skal have HTML-forhåndsvisning + +**Automatisk:** +- Filtype og størrelse detekteres automatisk +- HTML-forhåndsvisning kan genereres automatisk fra PDF (kræver PDF-til-HTML konvertering i backend) +- Ikon vælges automatisk ud fra filtype + +### 6. Kontaktoplysninger + +**Redaktøropgave:** Vælg ansvarlig afdeling fra liste. + +**Automatisk:** +- Adresse, telefon og e-mail trækkes fra kontaktregister baseret på valgt afdeling + +### 7. Høringssvar og kommentarer + +**Fuldt automatisk.** Borgere indsender via formularen. Kræver ingen redaktørindsats. + +**Redaktøropgave (valgfri):** +- Moderation af upassende indhold +- Tildeling af kategori til høringssvar (hvis ikke borgeren selv vælger) + +### 8. Statistik + +**Fuldt automatisk.** Alle tre statistiksektioner (linjediagram, kategorifordeling, kort) genereres fra de indkomne høringssvar. + +**Forudsætninger:** +- Linjediagram: hvert svar har en indsendt-dato → aggregeres per dag +- Kategorifordeling: hvert svar har en kategori → aggregeres per kategori +- Kort: hvert svar har en afsender-lokation (postnummer eller adresse) → geokodes og vises + +### 9. Info-boks (Mere viden) + +**Redaktøropgave:** Vælg 2-4 links til relevante sider fra vidensbasen. + +**Mulighed for automatisering:** Links kan foreslås automatisk baseret på høringstype (fx "lokalplan" → vis altid links om lokalplanprocessen). + +### 10. Relaterede aktiviteter + +**Redaktøropgave:** Knyt høringen til relaterede dialoger, høringer eller aktiviteter. + +**Automatisk:** +- Billede, titel, type, dato, svar-antal og lokation trækkes fra den relaterede aktivitets egen data +- Redaktøren behøver kun at vælge relationen — resten vises automatisk + +--- + +## Systembehov for automatisering + +For at maksimere den automatiske indholdsgenerering kræves: + +| System / data | Bruges til | +|---------------|------------| +| Byrådets dagsordensystem (API) | Afgørelsesdato, referat-PDF, video-link | +| Dokumentsystem | Vedtagne lokalplaner, materialefiler | +| Central ordliste i CMS | Glossary-forklaringer og links | +| Kontaktregister | Afdelingsoplysninger | +| PDF-til-HTML konvertering | Forhåndsvisning af materialer | +| Geokodning af postnumre | Geografisk kort over høringssvar | +| Aktivitets-/høringsregister | Relaterede aktiviteter, metadata | + +--- + +## Estimeret redaktørtid per høring + +| Opgave | Estimat | +|--------|---------| +| Hero-billede og metadata | 5 min | +| Overskrift, manchet, brødtekst | 30-60 min | +| Markering af glossary-termer | 5-10 min | +| Upload af materialer | 10-15 min | +| Afgørelsestekst (efter vedtagelse) | 15-20 min | +| Relationer og info-links | 5 min | +| **Total** | **ca. 1-2 timer** | + +Resten genereres automatisk fra data. diff --git a/docs/projects/deltag-aarhus/index.md b/docs/projects/deltag-aarhus/index.md new file mode 100644 index 0000000..a29968a --- /dev/null +++ b/docs/projects/deltag-aarhus/index.md @@ -0,0 +1,82 @@ +**Project:** deltag.aarhus.dk · **Status:** Draft · **Date:** April 2026 + +# deltag.aarhus.dk — Høringsdetalje + +**Prototype af en høringsdetalje-side til Aarhus Kommunes borgerdeltagelsesplatform.** + +--- + +## Baggrund + +deltag.aarhus.dk skal give borgere mulighed for at deltage i offentlige høringer, dialoger og andre demokratiske processer. Denne prototype demonstrerer en høringsdetalje-side — den side borgerne ser når de klikker ind på en konkret høring. + +Prototypen bruger et realistisk scenarie: en høring om vindmøller ved Vosnæs (Lokalplan nr. 1237 med miljøvurderingsrapport), med 784 simulerede høringssvar. + +--- + +## Hvad prototypen viser + +### Variantskift (åben/afsluttet) + +Prototypen kan skifte mellem to tilstande via mock-banneret: + +- **Åben høring** — borgere kan indsende høringssvar og kommentere andres svar +- **Afsluttet høring** — svarfristen er udløbet, "Skriv et høringssvar"-knappen er deaktiveret, og afgørelsesbannerets vises + +### Høringssvar + +- 784 simulerede høringssvar i et responsivt 4-kolonne grid +- Filtrering efter kategori (Miljø/Natur, Støj/Sundhed, Landskab/Visuel, Proces/Andet) +- Sortering (Nyeste, Ældste, Flest synes om, Flest kommentarer) +- Kontinuerlig "Vis flere"-indlæsning (16 ad gangen) +- Modal med fuldt svarindhold, kommentarer og svar-formuler +- Tastaturnavigation (piletaster, Escape) +- URL-dyblink til individuelt svar (`#svar-{id}`) + +### MitID login og indsendelse + +- Mock MitID-loginflow (åben variant) +- Indsendelsesformular med kategori, titel og brødtekst +- Kommentarformular på individuelle høringssvar + +### Statistik og kort + +- SVG-linjediagram over indsendte svar pr. dag (10-ugers høringsperiode) +- Kategorifordeling +- Interaktivt kort (Leaflet.js) med Vosnæs-koordinater + +### Øvrige features + +- Ordforklaringer (glossary) med tooltips på fagtermer +- Afgørelsesmodal med mødereferat, video og hvidbog +- Materialeliste med dokumentforhåndsvisning +- Relaterede aktiviteter (høringer og dialoger) +- Fuldt responsivt layout (mobil, tablet, desktop) +- Tilgængelig: ARIA-attributter, fokusstyring, tastaturnavigation + +--- + +## Teknisk opbygning + +Prototypen er vanilla HTML/CSS/JS uden build-trin: + +- **HTML:** Én `index.html` med semantisk markup +- **CSS:** 24 komponent-filer + designtokens med 93 custom properties +- **JS:** 15 moduler med centraliseret state management (`window.DeltagMock.state`) +- **Data:** 784 procedurelt genererede høringssvar med 15 kommentarer hver + +--- + +## Redaktionelt indhold + +Se [Redaktionelt indhold — Høringsdetalje side](editor-content-requirements.md) for en oversigt over hvad redaktører skal levere per høring, og hvad der kan genereres automatisk. + +**Estimat:** ca. 1–2 timer redaktørtid per høring (efter systemintegrationer er bygget). + +--- + +## Interaktiv prototype + +Åbn prototypen ↗ + +Prøv at skifte mellem åben og afsluttet variant via linkene i det blå mock-banner øverst. diff --git a/docs/projects/deltag-aarhus/mocks.md b/docs/projects/deltag-aarhus/mocks.md new file mode 100644 index 0000000..f01cac1 --- /dev/null +++ b/docs/projects/deltag-aarhus/mocks.md @@ -0,0 +1,10 @@ +**Project:** deltag.aarhus.dk + +# Interaktive Mocks + +Interaktive HTML-prototyper der demonstrerer den foreslåede høringsdetalje-side. Åbn dem for at afprøve interaktionerne direkte i browseren. + +--- + +**Høringsdetalje — Vindmøller ved Vosnæs ↗** +Komplet høringsdetalje-side med 784 simulerede høringssvar, filtrering, sortering, MitID-login, indsendelsesformular, statistik, kort, ordforklaringer og afgørelsesmodal. Skift mellem åben og afsluttet variant via mock-banneret. diff --git a/docs/projects/salary-negotiation/estimeringsnotat.md b/docs/projects/salary-negotiation/estimeringsnotat.md index 75dee56..f68f49d 100644 --- a/docs/projects/salary-negotiation/estimeringsnotat.md +++ b/docs/projects/salary-negotiation/estimeringsnotat.md @@ -1,6 +1,6 @@ --- protected: true -passwordHash: "9bf67668583e1070cfecddfca89e1e67fcd583dfb43c3ea79ec63ecf598136ae" +passwordHash: "92b0332dda228edf8ebd0208937b772f02625380fbb04a63d90b97662b183661" passwordGroup: "salary-negotiation" --- diff --git a/docs/projects/salary-negotiation/index.md b/docs/projects/salary-negotiation/index.md index 76fcc50..e35dbc2 100644 --- a/docs/projects/salary-negotiation/index.md +++ b/docs/projects/salary-negotiation/index.md @@ -1,7 +1,7 @@ --- title: Lønforhandlingssystem protected: true -passwordHash: "9bf67668583e1070cfecddfca89e1e67fcd583dfb43c3ea79ec63ecf598136ae" +passwordHash: "92b0332dda228edf8ebd0208937b772f02625380fbb04a63d90b97662b183661" passwordGroup: "salary-negotiation" --- diff --git a/docs/projects/salary-negotiation/mocks.md b/docs/projects/salary-negotiation/mocks.md index a35b17f..1b46695 100644 --- a/docs/projects/salary-negotiation/mocks.md +++ b/docs/projects/salary-negotiation/mocks.md @@ -1,6 +1,6 @@ --- protected: true -passwordHash: "9bf67668583e1070cfecddfca89e1e67fcd583dfb43c3ea79ec63ecf598136ae" +passwordHash: "92b0332dda228edf8ebd0208937b772f02625380fbb04a63d90b97662b183661" passwordGroup: "salary-negotiation" --- diff --git a/docs/public/projects/deltag-aarhus/mocks/AAK_02_hoejrejusteret_dark.svg b/docs/public/projects/deltag-aarhus/mocks/AAK_02_hoejrejusteret_dark.svg new file mode 100644 index 0000000..df0d51f --- /dev/null +++ b/docs/public/projects/deltag-aarhus/mocks/AAK_02_hoejrejusteret_dark.svg @@ -0,0 +1,21 @@ + diff --git a/docs/public/projects/deltag-aarhus/mocks/AAK_02_venstrejusteret_hvid.svg b/docs/public/projects/deltag-aarhus/mocks/AAK_02_venstrejusteret_hvid.svg new file mode 100644 index 0000000..aad9e73 --- /dev/null +++ b/docs/public/projects/deltag-aarhus/mocks/AAK_02_venstrejusteret_hvid.svg @@ -0,0 +1,30 @@ + diff --git a/docs/public/projects/deltag-aarhus/mocks/AAK_02_venstrejusteret_sh.svg b/docs/public/projects/deltag-aarhus/mocks/AAK_02_venstrejusteret_sh.svg new file mode 100644 index 0000000..b75cf6b --- /dev/null +++ b/docs/public/projects/deltag-aarhus/mocks/AAK_02_venstrejusteret_sh.svg @@ -0,0 +1,30 @@ + diff --git a/docs/public/projects/deltag-aarhus/mocks/css/base.css b/docs/public/projects/deltag-aarhus/mocks/css/base.css new file mode 100644 index 0000000..05daa6c --- /dev/null +++ b/docs/public/projects/deltag-aarhus/mocks/css/base.css @@ -0,0 +1,109 @@ +/* Global reset, base element styles, and utility classes. + Container patterns used across components: + - Centered: max-width: var(--container-max); margin: 0 auto; padding-inline: 116px; + - Edge-aware: margin-inline: max(40px, calc((100% - var(--container-max)) / 2)); + The second pattern guarantees minimum 40px side margin at any viewport width. */ + +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +html { + font-size: 16px; + -webkit-text-size-adjust: 100%; + scroll-behavior: smooth; +} + +body { + font-family: var(--font-family); + font-size: var(--fs-base); + font-weight: var(--fw-regular); + line-height: var(--lh-body); + color: var(--text-primary); + background-color: var(--bg-primary); + letter-spacing: 0.05em; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +body.modal-open { + overflow: hidden; +} + +img { + display: block; + max-width: 100%; + height: auto; +} + +a { + color: var(--text-link); + text-decoration: underline; + transition: color var(--transition-fast); +} + +a:hover { + color: var(--text-link-hover); +} + +button { + font-family: inherit; + font-size: inherit; + cursor: pointer; + border: none; + background: none; +} + +h1, h2, h3, h4, h5, h6 { + font-weight: var(--fw-bold); + line-height: var(--lh-heading); + color: var(--text-primary); +} + +p { + max-width: 45rem; +} + +ul, ol { + list-style: none; +} + +:focus-visible { + outline: 2px solid var(--petroleum); + outline-offset: 2px; +} + +/* Layout utilities */ + +.container { + max-width: var(--container-max); + margin-inline: auto; + padding-inline: calc(var(--spacer) * 1.5); +} + +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} + +@media (prefers-reduced-motion: reduce) { + *, + *::before, + *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + scroll-behavior: auto !important; + } +} diff --git a/docs/public/projects/deltag-aarhus/mocks/css/body-section.css b/docs/public/projects/deltag-aarhus/mocks/css/body-section.css new file mode 100644 index 0000000..e3c6b4d --- /dev/null +++ b/docs/public/projects/deltag-aarhus/mocks/css/body-section.css @@ -0,0 +1,100 @@ +/* Body Section — main content area with two-column grid layout and contact card sidebar */ + +.body-section { + max-width: var(--container-max); + /* Edge-aware centering; switches to margin: 0 auto at 960px when sidebar stacks */ + margin: 0 max(40px, calc((100% - var(--container-max)) / 2)); + padding: 48px 116px 0; + display: grid; + grid-template-columns: 1fr auto; + gap: 60px; +} + +.body-section__content { + display: flex; + flex-direction: column; + gap: 32px; +} + +.body-section__text { + font-size: var(--fs-base); + line-height: 24px; +} + +.body-section__text p + p { + margin-top: 16px; +} + +.body-section__dates { + display: flex; + gap: 32px; + font-family: var(--font-family-inter); + font-size: var(--fs-base); + color: #474747; +} + +.body-section__dates strong { + color: var(--black); + font-weight: var(--fw-regular); +} + +/* Contact Card */ +.contact-card { + background: var(--petroleum-100); + border-bottom: 2px solid var(--petroleum-200); + border-radius: 3px; + padding: 40px; + overflow: hidden; + display: flex; + flex-direction: column; + gap: 16px; + width: 340px; + align-self: start; +} + +.contact-card__department { + font-size: var(--fs-small); + font-weight: var(--fw-bold); + color: var(--petroleum); +} + +.contact-card__name { + font-size: 18px; + font-weight: var(--fw-bold); +} + +.contact-card__details { + font-size: var(--fs-base); + display: flex; + flex-direction: column; + gap: 12px; + line-height: 1.5; +} + +.contact-card__details a { + color: var(--text-primary); +} + +@media (max-width: 1200px) { + .body-section { + padding: 48px 40px 0; + } +} + +@media (max-width: 960px) { + .body-section { + grid-template-columns: 1fr; + margin: 0 auto; + padding: 32px 40px 0; + } + + .contact-card { + width: 100%; + } +} + +@media (max-width: 640px) { + .body-section { + padding: 32px 16px 0; + } +} diff --git a/docs/public/projects/deltag-aarhus/mocks/css/decision-banner.css b/docs/public/projects/deltag-aarhus/mocks/css/decision-banner.css new file mode 100644 index 0000000..6ba6772 --- /dev/null +++ b/docs/public/projects/deltag-aarhus/mocks/css/decision-banner.css @@ -0,0 +1,44 @@ +/* Decision Banner — yellow notification banner for hearing decisions */ + +.decision-banner { + max-width: var(--container-max); + /* Pulls banner up over the hero image; edge-aware centering guarantees 40px minimum side margin */ + margin: -60px max(40px, calc((100% - var(--container-max)) / 2)) 0; + position: relative; + z-index: 1; + background: var(--yellow-50); + border-bottom: 8px solid var(--yellow-100); + border-radius: 4px; + padding: 16px 116px 24px; +} + +.decision-banner__title { + font-size: 24px; + font-weight: var(--fw-regular); + line-height: 36px; + color: var(--black); +} + +.decision-banner__text { + font-family: var(--font-family-inter); + font-size: var(--fs-base); + line-height: 24px; + color: var(--black); +} + +.decision-banner__link { + color: var(--black); +} + +@media (max-width: 1200px) { + .decision-banner { + padding: 16px 60px 24px; + } +} + +@media (max-width: 640px) { + .decision-banner { + padding: 16px 24px 24px; + margin-inline: 16px; + } +} diff --git a/docs/public/projects/deltag-aarhus/mocks/css/footer.css b/docs/public/projects/deltag-aarhus/mocks/css/footer.css new file mode 100644 index 0000000..fc2668f --- /dev/null +++ b/docs/public/projects/deltag-aarhus/mocks/css/footer.css @@ -0,0 +1,78 @@ +/* Footer — site footer with three-column layout, contact info, and bottom links */ + +.footer { + background: var(--gray-900); + color: var(--white); + padding: 48px 0 0; + position: relative; +} + +.footer__inner { + max-width: var(--container-max); + margin: 0 auto; + padding: 0 135px; + display: grid; + grid-template-columns: 1fr 1fr 1fr; + gap: 48px; +} + +.footer__col-title { + font-size: 18px; + font-weight: var(--fw-bold); + margin-bottom: 24px; +} + +.footer__text { + font-size: var(--fs-small); + line-height: 20px; +} + +.footer__text + .footer__text { + margin-top: 8px; +} + +.footer__phone { + font-size: var(--fs-base); + font-weight: var(--fw-bold); + text-transform: uppercase; + margin-top: 24px; +} + +.footer__logo { + margin-top: 32px; +} + +.footer__logo svg { + height: 40px; + width: auto; + fill: var(--white); +} + +.footer__bottom { + max-width: var(--container-max); + margin: 0 auto; + padding: 32px 135px; + border-top: 1px solid var(--gray-600); + margin-top: 32px; +} + +.footer__bottom-links { + font-size: var(--fs-small); + color: var(--gray-600); +} + +.footer__bottom-links a { + color: var(--gray-600); + text-decoration: none; +} + +.footer__bottom-links a:hover { + color: var(--white); +} + +@media (max-width: 960px) { + .footer__inner { + grid-template-columns: 1fr; + padding: 0 24px; + } +} diff --git a/docs/public/projects/deltag-aarhus/mocks/css/glossary.css b/docs/public/projects/deltag-aarhus/mocks/css/glossary.css new file mode 100644 index 0000000..fb8653b --- /dev/null +++ b/docs/public/projects/deltag-aarhus/mocks/css/glossary.css @@ -0,0 +1,55 @@ +/* Glossary — inline term definitions with tooltip popups */ + +.glossary-term { + position: relative; + display: inline; + border-bottom: 1px dashed var(--petroleum); +} + +.glossary-term__icon { + display: inline-flex; + align-items: center; + justify-content: center; + background: none; + border: none; + cursor: pointer; + color: var(--petroleum); + font-size: 14px; + padding: 0 2px; + vertical-align: super; + line-height: 1; +} + +.glossary-term__icon:hover { + color: var(--petroleum-800); +} + +.glossary-term__tooltip { + display: none; + position: absolute; + bottom: calc(100% + 8px); + left: 50%; + transform: translateX(-50%); + background: var(--white); + border: 1px solid var(--border-default); + box-shadow: 0 4px 16px rgb(0 0 0 / 12%); + padding: 16px; + width: 320px; + font-family: var(--font-family-inter); + font-size: var(--fs-small); + line-height: 20px; + color: var(--text-primary); + z-index: 100; + border-radius: 8px; +} + +.glossary-term__tooltip a { + display: block; + margin-top: 8px; + color: var(--petroleum); + font-weight: var(--fw-semibold); +} + +.glossary-term--open > .glossary-term__tooltip { + display: block; +} diff --git a/docs/public/projects/deltag-aarhus/mocks/css/hearing-header.css b/docs/public/projects/deltag-aarhus/mocks/css/hearing-header.css new file mode 100644 index 0000000..4a3c2fd --- /dev/null +++ b/docs/public/projects/deltag-aarhus/mocks/css/hearing-header.css @@ -0,0 +1,150 @@ +/* Hearing Header — teal header block with title, lead text, and metadata sidebar */ + +.hearing-header { + max-width: var(--container-max); + /* Edge-aware centering: auto-centers above container-max, 40px minimum below */ + margin: 24px max(40px, calc((100% - var(--container-max)) / 2)) 0; + position: relative; + z-index: 1; + background: var(--petroleum-100); + border-bottom: 8px solid var(--petroleum-200); + border-radius: 4px; + padding: 60px 116px; + display: flex; + flex-direction: column; + gap: 24px; +} + +.hearing-header__label { + font-size: var(--fs-small); + font-weight: var(--fw-bold); + color: var(--petroleum); +} + +.hearing-header__content { + display: flex; + /* Matches design comp spacing */ + gap: 27px; +} + +.hearing-header__main { + flex: 1; + display: flex; + flex-direction: column; + gap: 27px; + /* Constrains text column width per design grid */ + max-width: 734px; +} + +.hearing-header__title { + font-size: 40px; + font-weight: var(--fw-bold); + line-height: 1.2; +} + +.hearing-header__lead { + font-size: 24px; + line-height: 36px; + color: var(--text-primary); +} + +.hearing-header__sidebar { + width: 208px; + flex-shrink: 0; + border-left: 2px solid var(--petroleum-200); + display: flex; + flex-direction: column; + gap: 27px; +} + +.hearing-header__meta-item { + padding-left: 24px; +} + +.hearing-header__meta-label { + display: flex; + gap: 8px; + align-items: center; + color: var(--petroleum-muted); + font-family: var(--font-family-inter); + font-size: var(--fs-base); + line-height: 24px; +} + +.hearing-header__meta-label i { + width: 16px; + text-align: center; + line-height: 1; +} + +.hearing-header__meta-value { + font-family: var(--font-family-inter); + font-size: var(--fs-base); + font-weight: var(--fw-semibold); + line-height: 24px; + padding-left: 24px; + margin-top: 2px; +} + +/* Project link in sidebar */ +.hearing-header__meta-link { + color: var(--petroleum); + text-decoration: underline; + font-weight: var(--fw-semibold); +} + +.hearing-header__meta-link:hover { + color: var(--petroleum-800); +} + +.hearing-header__tags { + font-family: var(--font-family-inter); + font-size: var(--fs-base); + font-weight: var(--fw-semibold); + color: var(--petroleum-muted); + line-height: 24px; +} + +@media (max-width: 1200px) { + .hearing-header { + padding: 40px 60px; + } +} + +@media (max-width: 960px) { + .hearing-header__content { + flex-direction: column; + } + + .hearing-header__sidebar { + width: 100%; + border-left: none; + border-top: 2px solid var(--petroleum-200); + padding-top: 24px; + flex-direction: row; + flex-wrap: wrap; + } + + .hearing-header__meta-item { + padding-left: 0; + } +} + +@media (max-width: 640px) { + .hearing-header { + padding: 24px; + } + + .hearing-header__title { + font-size: 28px; + } + + .hearing-header__lead { + font-size: 18px; + line-height: 28px; + } + + .hearing-header { + margin-inline: 16px; + } +} diff --git a/docs/public/projects/deltag-aarhus/mocks/css/hero.css b/docs/public/projects/deltag-aarhus/mocks/css/hero.css new file mode 100644 index 0000000..6fabf67 --- /dev/null +++ b/docs/public/projects/deltag-aarhus/mocks/css/hero.css @@ -0,0 +1,14 @@ +/* Hero — full-width hero image section */ + +.hero { + width: 100%; + height: 500px; + overflow: hidden; + position: relative; +} + +.hero__image { + width: 100%; + height: 100%; + object-fit: cover; +} diff --git a/docs/public/projects/deltag-aarhus/mocks/css/horingssvar.css b/docs/public/projects/deltag-aarhus/mocks/css/horingssvar.css new file mode 100644 index 0000000..811faf2 --- /dev/null +++ b/docs/public/projects/deltag-aarhus/mocks/css/horingssvar.css @@ -0,0 +1,292 @@ +/* Horingssvar — hearing responses section with card grid, dropdowns, pagination, and submit button */ + +.horingssvar-section { + max-width: var(--container-max); + margin: 0 auto; + padding: 0 116px 48px; +} + +.horingssvar-section__header { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: 16px; + margin-bottom: 24px; +} + +.horingssvar-section__title { + font-size: var(--fs-teaser); + font-weight: var(--fw-bold); + margin-right: auto; +} + +.horingssvar-section__controls { + display: flex; + align-items: center; + gap: 32px; + flex-wrap: wrap; + width: 100%; + margin-bottom: 32px; +} + +/* Dropdown */ +.dropdown { + position: relative; + display: inline-block; +} + +.dropdown__button { + display: flex; + align-items: center; + gap: 10px; + font-size: 20px; + color: var(--black); + padding: 4px 0; + background: none; + border: none; + cursor: pointer; + font-family: var(--font-family); +} + +.dropdown__button i { + font-size: var(--fs-base); +} + +.dropdown__menu { + display: none; + position: absolute; + top: 100%; + left: 0; + /* Above card content, below nav (100) */ + z-index: 20; + background: var(--white); + border: 1px solid var(--border-default); + box-shadow: var(--shadow-card); + min-width: 200px; + padding: 8px 0; +} + +.dropdown__menu--open { + display: block; +} + +.dropdown__item { + display: block; + width: 100%; + text-align: left; + padding: 8px 16px; + font-size: var(--fs-base); + color: var(--text-primary); + background: none; + border: none; + cursor: pointer; + font-family: var(--font-family); +} + +.dropdown__item:hover { + background: var(--gray-100); +} + +.dropdown__item--active { + font-weight: var(--fw-bold); + color: var(--petroleum); +} + +.btn-primary { + display: inline-flex; + align-items: center; + justify-content: center; + background: var(--petroleum); + color: var(--white); + font-family: var(--font-family-inter); + font-size: var(--fs-base); + font-weight: var(--fw-regular); + padding: 8px 24px; + border: 1px solid var(--petroleum); + border-radius: 4px; + text-decoration: none; + cursor: pointer; + transition: background var(--transition-fast); + line-height: 24px; + margin-left: auto; +} + +.btn-primary:hover { + background: var(--petroleum-800); + color: var(--white); +} + +/* Card Grid */ +.horingssvar-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 24px; + margin-bottom: 48px; +} + +/* Horingssvar Card */ +.horingssvar-card { + background: var(--white); + border: 1px solid var(--gray-200); + border-radius: 4px; + padding: 24px 20px; + min-height: 240px; + display: flex; + flex-direction: column; + gap: 18px; + cursor: pointer; + transition: box-shadow var(--transition-card-in), + transform var(--transition-card-in); +} + +.horingssvar-card:hover { + box-shadow: var(--shadow-card); + /* Subtle lift on hover for depth feedback */ + transform: translateY(-2px); + transition: box-shadow var(--transition-card-out), + transform var(--transition-card-out); +} + +.horingssvar-card__title { + font-family: var(--font-family-inter); + font-size: 18px; + font-weight: var(--fw-semibold); + line-height: 28px; + color: var(--text-primary); +} + +.horingssvar-card__description { + font-family: var(--font-family-inter); + font-size: var(--fs-small); + line-height: 20px; + color: var(--text-primary); + overflow: hidden; + display: -webkit-box; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; + height: 61px; +} + +.horingssvar-card__meta { + display: flex; + flex-direction: column; + gap: 8px; + font-family: var(--font-family-inter); + font-size: var(--fs-small); + line-height: 20px; + color: var(--text-primary); +} + +.horingssvar-card__meta-item { + display: flex; + align-items: center; + gap: 8px; +} + +.horingssvar-card__meta-item i { + width: 14px; + text-align: center; + color: var(--gray-600); +} + +/* Like button (open variant) */ +.horingssvar-card__like-btn { + display: flex; + align-items: center; + gap: 8px; + font-family: var(--font-family-inter); + font-size: var(--fs-small); + line-height: 20px; + color: var(--text-primary); + background: none; + border: none; + padding: 0; + cursor: pointer; +} + +.horingssvar-card__like-btn:hover { + color: var(--petroleum); +} + +.horingssvar-card__like-btn--liked { + color: var(--petroleum); + cursor: default; +} + +.horingssvar-card__divider { + height: 1px; + background: var(--gray-200); + margin-top: auto; +} + +/* Pagination */ +.horingssvar-pagination { + display: flex; + justify-content: center; + align-items: baseline; + gap: 8px; + font-family: var(--font-family-inter); + font-size: 18px; + font-weight: var(--fw-semibold); + padding-bottom: 16px; + border-bottom: 1px solid var(--gray-200); +} + +.horingssvar-pagination__count { + color: var(--gray-650); +} + +.horingssvar-pagination__show-all { + color: var(--petroleum); + text-decoration: underline; + cursor: pointer; + background: none; + border: none; + font-family: var(--font-family-inter); + font-size: 18px; + font-weight: var(--fw-semibold); +} + +.horingssvar-pagination__show-all:hover { + color: var(--petroleum-800); +} + +@media (max-width: 1200px) { + .horingssvar-grid { + grid-template-columns: repeat(2, 1fr); + } + + .horingssvar-section { + padding: 0 40px 48px; + } +} + +@media (max-width: 960px) { + .horingssvar-grid { + grid-template-columns: repeat(2, 1fr); + } +} + +@media (max-width: 640px) { + .horingssvar-grid { + grid-template-columns: 1fr; + } + + .horingssvar-section { + padding: 0 16px 48px; + } + + .horingssvar-section__controls { + flex-direction: column; + align-items: flex-start; + } + + .btn-primary { + margin-left: 0; + width: 100%; + } + + .dropdown__button { + font-size: 18px; + } +} diff --git a/docs/public/projects/deltag-aarhus/mocks/css/info-box.css b/docs/public/projects/deltag-aarhus/mocks/css/info-box.css new file mode 100644 index 0000000..3ea92d8 --- /dev/null +++ b/docs/public/projects/deltag-aarhus/mocks/css/info-box.css @@ -0,0 +1,49 @@ +/* Info Box — blue highlighted information panel with header and body */ + +.info-box { + max-width: 787px; + margin: 0 auto 48px; + padding-inline: 116px; + max-width: var(--container-max); +} + +.info-box__header { + background: var(--blue-200); + padding: 12px 32px; + display: flex; + align-items: center; + min-height: 67px; + border-radius: 4px 4px 0 0; +} + +.info-box__title { + font-family: var(--font-family-inter); + font-size: 20px; + font-weight: var(--fw-semibold); + color: var(--black); +} + +.info-box__body { + background: var(--blue-50); + padding: 32px; + border-radius: 0 0 4px 4px; +} + +.info-box__body p { + font-family: var(--font-family-inter); + font-size: var(--fs-base); + line-height: 24px; +} + +.info-box__body a { + color: var(--black); + display: block; + line-height: 24px; +} + +@media (max-width: 1200px) { + .info-box { + margin-left: 40px; + margin-right: 40px; + } +} diff --git a/docs/public/projects/deltag-aarhus/mocks/css/map.css b/docs/public/projects/deltag-aarhus/mocks/css/map.css new file mode 100644 index 0000000..0cb2961 --- /dev/null +++ b/docs/public/projects/deltag-aarhus/mocks/css/map.css @@ -0,0 +1,24 @@ +/* Map — embedded map section with bordered container */ + +.map-box-section { + max-width: var(--container-max); + margin: 0 auto; + padding: 0 116px 48px; + position: relative; + z-index: 1; +} + +.map-box { + width: 100%; + height: 450px; + border-radius: 4px; + overflow: hidden; + z-index: 1; + position: relative; +} + +@media (max-width: 1200px) { + .map-box-section { + padding-inline: 40px; + } +} diff --git a/docs/public/projects/deltag-aarhus/mocks/css/materials.css b/docs/public/projects/deltag-aarhus/mocks/css/materials.css new file mode 100644 index 0000000..5a1fc53 --- /dev/null +++ b/docs/public/projects/deltag-aarhus/mocks/css/materials.css @@ -0,0 +1,89 @@ +/* Materials — downloadable documents/files list section */ + +.materials-section { + max-width: var(--container-max); + margin: 0 auto; + /* Right padding includes 400px for sidebar+gap alignment with body-section above */ + padding: 32px calc(116px + 400px) 48px 116px; +} + +.materials__heading { + font-size: var(--fs-teaser); + font-weight: var(--fw-bold); + margin-bottom: 16px; +} + +.materials__list { + display: flex; + flex-direction: column; + gap: 4px; +} + +.materials__item { + display: flex; + align-items: center; + gap: 12px; + background: var(--petroleum-100); + padding: 6px 18px; + height: 50px; + text-decoration: none; + color: var(--text-primary); + transition: background var(--transition-fast); +} + +.materials__item:hover { + background: var(--petroleum-200); + color: var(--text-primary); +} + +.materials__item-name { + font-weight: var(--fw-bold); + font-size: var(--fs-small); + white-space: nowrap; +} + +.materials__item-meta { + display: flex; + align-items: center; + gap: 6px; + color: var(--gray-650); +} + +.materials__item-preview-badge { + display: inline-flex; + align-items: center; + gap: 4px; + font-size: var(--fs-xs); + font-weight: var(--fw-semibold); + color: var(--petroleum); + background: var(--petroleum-100); + padding: 2px 8px; + border-radius: 4px; +} + +.materials__item-icon { + font-size: 14px; +} + +.materials__item-size { + font-size: var(--fs-xs); +} + +@media (max-width: 1200px) { + .materials-section { + /* Maintains sidebar-width offset at tablet */ + padding: 32px calc(40px + 400px) 48px 40px; + } +} + +@media (max-width: 960px) { + .materials-section { + padding: 24px 40px 32px; + } +} + +@media (max-width: 640px) { + .materials-section { + padding: 24px 16px 32px; + } +} diff --git a/docs/public/projects/deltag-aarhus/mocks/css/mock-banner.css b/docs/public/projects/deltag-aarhus/mocks/css/mock-banner.css new file mode 100644 index 0000000..b13ec98 --- /dev/null +++ b/docs/public/projects/deltag-aarhus/mocks/css/mock-banner.css @@ -0,0 +1,44 @@ +/* Mock Banner — red development/staging indicator banner at top of page */ + +.mock-banner { + position: sticky; + top: 0; + z-index: 200; + background: #d32f2f; + color: #fff; + text-align: center; + font-family: var(--font-family-inter); + font-size: var(--fs-xs); + font-weight: var(--fw-semibold); + padding: 6px 16px; + letter-spacing: 0.5px; +} + +.mock-banner__link { + color: #fff; + text-decoration: underline; + margin-left: 4px; +} + +.mock-banner__link:hover { + color: #ffcdd2; +} + +.mock-banner__divider { + margin: 0 8px; + opacity: 0.5; +} + +.mock-banner__variants { + margin-left: 8px; +} + +.mock-banner__link--variant { + margin: 0 4px; +} + +.mock-banner__link--active { + text-decoration: none; + border-bottom: 2px solid #fff; + padding-bottom: 1px; +} diff --git a/docs/public/projects/deltag-aarhus/mocks/css/modal-decision.css b/docs/public/projects/deltag-aarhus/mocks/css/modal-decision.css new file mode 100644 index 0000000..78d7b2f --- /dev/null +++ b/docs/public/projects/deltag-aarhus/mocks/css/modal-decision.css @@ -0,0 +1,41 @@ +/* Modal Decision — decision modal with related document links */ + +.decision-modal__links { + border-top: 1px solid var(--gray-200); + padding-top: 24px; + display: flex; + flex-direction: column; + gap: 12px; +} + +.decision-modal__links-title { + font-family: var(--font-family-inter); + font-size: var(--fs-base); + font-weight: var(--fw-semibold); + margin-bottom: 4px; +} + +.decision-modal__link { + display: flex; + align-items: center; + gap: 12px; + padding: 12px 16px; + background: var(--gray-100); + text-decoration: none; + color: var(--text-primary); + font-family: var(--font-family-inter); + font-size: var(--fs-small); + transition: background var(--transition-fast); +} + +.decision-modal__link:hover { + background: var(--gray-200); +} + +.decision-modal__link i { + color: var(--petroleum); + font-size: 18px; + width: 24px; + text-align: center; + flex-shrink: 0; +} diff --git a/docs/public/projects/deltag-aarhus/mocks/css/modal-horingssvar.css b/docs/public/projects/deltag-aarhus/mocks/css/modal-horingssvar.css new file mode 100644 index 0000000..f4977e7 --- /dev/null +++ b/docs/public/projects/deltag-aarhus/mocks/css/modal-horingssvar.css @@ -0,0 +1,126 @@ +/* Modal Horingssvar — hearing response modal with stats, comments section, and show-more button */ + +.modal__stats { + display: flex; + gap: 24px; + padding-top: 16px; + border-top: 1px solid var(--gray-200); + font-family: var(--font-family-inter); + font-size: var(--fs-small); + color: var(--text-primary); +} + +.modal__stat { + display: flex; + align-items: center; + gap: 8px; +} + +.modal__stat i { + color: var(--gray-600); +} + +/* Interactive like stat (open variant) */ +.modal__stat--interactive:hover { + color: var(--petroleum); +} + +.modal__stat--liked { + color: var(--petroleum); +} + +.modal__comments-section { + border-top: 1px solid var(--gray-200); + padding-top: 24px; + display: flex; + flex-direction: column; + gap: 16px; +} + +.modal__comments-title { + font-family: var(--font-family-inter); + font-size: var(--fs-base); + font-weight: var(--fw-semibold); +} + +.modal__comment { + padding: 16px; + background: var(--gray-100); + display: flex; + flex-direction: column; + gap: 8px; +} + +.modal__comment-author { + font-family: var(--font-family-inter); + font-size: var(--fs-small); + font-weight: var(--fw-semibold); +} + +.modal__comment-date { + font-family: var(--font-family-inter); + font-size: var(--fs-xs); + color: var(--gray-650); +} + +.modal__comment-text { + font-family: var(--font-family-inter); + font-size: var(--fs-small); + line-height: 20px; +} + +.modal__comments-show-more { + font-family: var(--font-family-inter); + font-size: var(--fs-small); + font-weight: var(--fw-semibold); + color: var(--petroleum); + background: none; + border: 1px solid var(--petroleum); + padding: 10px 20px; + cursor: pointer; + transition: background var(--transition-fast), color var(--transition-fast); + align-self: center; +} + +.modal__comments-show-more:hover { + background: var(--petroleum); + color: var(--white); +} + +/* Comment form (open variant only) */ +.modal__comment-form { + display: flex; + flex-direction: column; + gap: 10px; + padding-top: 16px; + border-top: 1px solid var(--gray-200); + margin-top: 8px; +} + +.modal__comment-form-label { + font-family: var(--font-family-inter); + font-size: var(--fs-small); + font-weight: var(--fw-semibold); +} + +.modal__comment-input { + width: 100%; + min-height: 80px; + padding: 12px; + border: 1px solid var(--border-default); + border-radius: 4px; + font-family: var(--font-family); + font-size: var(--fs-small); + resize: vertical; +} + +.modal__comment-input:focus { + outline: 2px solid var(--petroleum); + outline-offset: -1px; + border-color: var(--petroleum); +} + +.modal__comment-submit { + align-self: flex-end; + padding: 8px 20px; +} diff --git a/docs/public/projects/deltag-aarhus/mocks/css/modal-material.css b/docs/public/projects/deltag-aarhus/mocks/css/modal-material.css new file mode 100644 index 0000000..8f76ed6 --- /dev/null +++ b/docs/public/projects/deltag-aarhus/mocks/css/modal-material.css @@ -0,0 +1,49 @@ +/* Modal Material — material document modal with action buttons and rich content */ + +.material-modal__actions { + display: flex; + gap: 12px; + padding-bottom: 16px; + border-bottom: 1px solid var(--gray-200); +} + +.material-modal__action-btn { + display: inline-flex; + align-items: center; + gap: 8px; + padding: 8px 16px; + font-family: var(--font-family-inter); + font-size: var(--fs-small); + font-weight: var(--fw-semibold); + color: var(--petroleum); + border: 1px solid var(--petroleum); + text-decoration: none; + transition: background var(--transition-fast), color var(--transition-fast); +} + +.material-modal__action-btn:hover { + background: var(--petroleum); + color: var(--white); +} + +.material-modal__content { + font-family: var(--font-family-inter); + font-size: var(--fs-small); + line-height: 22px; + color: var(--text-primary); +} + +.material-modal__content h3 { + font-size: var(--fs-base); + font-weight: var(--fw-semibold); + margin-top: 24px; + margin-bottom: 8px; +} + +.material-modal__content h3:first-child { + margin-top: 0; +} + +.material-modal__content p { + margin-bottom: 12px; +} diff --git a/docs/public/projects/deltag-aarhus/mocks/css/modal-mitid.css b/docs/public/projects/deltag-aarhus/mocks/css/modal-mitid.css new file mode 100644 index 0000000..f77eb9d --- /dev/null +++ b/docs/public/projects/deltag-aarhus/mocks/css/modal-mitid.css @@ -0,0 +1,96 @@ +/* Modal MitID — mock MitID login flow */ + +.modal--mitid { + max-width: 440px; +} + +.mitid-flow { + display: flex; + flex-direction: column; + align-items: center; + gap: 20px; + padding: 16px 0; + text-align: center; +} + +.mitid-flow__logo { + display: flex; + align-items: center; + gap: 10px; + color: #0060a3; + font-size: 28px; +} + +.mitid-flow__logo-text { + font-family: var(--font-family-inter); + font-size: 24px; + font-weight: var(--fw-bold); + color: #0060a3; +} + +.mitid-flow__description { + font-family: var(--font-family-inter); + font-size: var(--fs-small); + line-height: 1.5; + color: var(--text-primary); + max-width: 320px; +} + +.mitid-flow__field { + width: 100%; + max-width: 300px; + text-align: left; +} + +.mitid-flow__label { + display: block; + font-family: var(--font-family-inter); + font-size: var(--fs-xs); + font-weight: var(--fw-semibold); + color: var(--gray-650); + margin-bottom: 6px; +} + +.mitid-flow__input { + width: 100%; + padding: 10px 14px; + border: 1px solid var(--border-default); + border-radius: 4px; + font-family: var(--font-family-inter); + font-size: var(--fs-base); + background: var(--gray-100); + color: var(--text-primary); +} + +.mitid-flow__hint { + font-family: var(--font-family-inter); + font-size: var(--fs-xs); + color: var(--gray-650); +} + +.mitid-flow__approve { + display: inline-flex; + align-items: center; + justify-content: center; + background: #0060a3; + color: var(--white); + font-family: var(--font-family-inter); + font-size: var(--fs-base); + font-weight: var(--fw-semibold); + padding: 12px 48px; + border: none; + border-radius: 4px; + cursor: pointer; + transition: background var(--transition-fast); +} + +.mitid-flow__approve:hover { + background: #004a7f; +} + +.mitid-flow__note { + font-family: var(--font-family-inter); + font-size: var(--fs-xs); + color: var(--gray-400); + font-style: italic; +} diff --git a/docs/public/projects/deltag-aarhus/mocks/css/modal-submission.css b/docs/public/projects/deltag-aarhus/mocks/css/modal-submission.css new file mode 100644 index 0000000..dcd2dc2 --- /dev/null +++ b/docs/public/projects/deltag-aarhus/mocks/css/modal-submission.css @@ -0,0 +1,116 @@ +/* Modal Submission — høringssvar submission form */ + +.submission-form { + display: flex; + flex-direction: column; + gap: 20px; +} + +.submission-form__field { + display: flex; + flex-direction: column; + gap: 6px; +} + +.submission-form__label { + font-family: var(--font-family-inter); + font-size: var(--fs-small); + font-weight: var(--fw-semibold); + color: var(--text-primary); +} + +.submission-form__input, +.submission-form__select, +.submission-form__textarea { + width: 100%; + padding: 10px 14px; + border: 1px solid var(--border-default); + border-radius: 4px; + font-family: var(--font-family); + font-size: var(--fs-base); + color: var(--text-primary); + background: var(--white); +} + +.submission-form__input:read-only { + background: var(--gray-100); + color: var(--gray-650); +} + +.submission-form__textarea { + resize: vertical; + min-height: 120px; +} + +.submission-form__input:focus, +.submission-form__select:focus, +.submission-form__textarea:focus { + outline: 2px solid var(--petroleum); + outline-offset: -1px; + border-color: var(--petroleum); +} + +.submission-form__hint { + font-family: var(--font-family-inter); + font-size: var(--fs-xs); + color: var(--gray-650); + font-style: italic; +} + +.submission-form__notice { + display: flex; + gap: 12px; + padding: 14px 16px; + background: var(--gray-100); + border-radius: 4px; + font-family: var(--font-family-inter); + font-size: var(--fs-xs); + line-height: 1.5; + color: var(--gray-650); +} + +.submission-form__notice i { + flex-shrink: 0; + margin-top: 2px; + color: var(--gray-400); +} + +.submission-form__actions { + display: flex; + justify-content: flex-end; + padding-top: 8px; +} + +.submission-form__submit { + padding: 10px 32px; +} + +/* Success state shown after mock submission */ +.submission-success { + display: flex; + flex-direction: column; + align-items: center; + gap: 16px; + padding: 32px 16px; + text-align: center; +} + +.submission-success__icon { + font-size: 48px; + color: #2e7d32; +} + +.submission-success__title { + font-family: var(--font-family-inter); + font-size: var(--fs-teaser); + font-weight: var(--fw-bold); + color: var(--text-primary); +} + +.submission-success__text { + font-family: var(--font-family-inter); + font-size: var(--fs-small); + line-height: 1.5; + color: var(--gray-650); + max-width: 400px; +} diff --git a/docs/public/projects/deltag-aarhus/mocks/css/modal.css b/docs/public/projects/deltag-aarhus/mocks/css/modal.css new file mode 100644 index 0000000..28bdd35 --- /dev/null +++ b/docs/public/projects/deltag-aarhus/mocks/css/modal.css @@ -0,0 +1,169 @@ +/* Modal — shared base modal overlay, structure, header, body, meta, description, and navigation */ + +.modal-overlay { + display: none; + position: fixed; + inset: 0; + /* Above everything including nav (100) */ + z-index: 1000; + background: rgb(0 0 0 / 50%); + justify-content: center; + align-items: flex-start; + padding: 60px 20px; + overflow-y: auto; +} + +.modal-overlay--open { + display: flex; +} + +.modal { + background: var(--white); + width: 100%; + max-width: 800px; + /* Viewport minus overlay padding (60px top + 60px bottom) */ + max-height: calc(100vh - 120px); + position: relative; + box-shadow: 0 8px 32px rgb(0 0 0 / 20%); + display: flex; + flex-direction: column; +} + +.modal__header { + display: flex; + align-items: flex-start; + justify-content: space-between; + padding: 40px 40px 0; + gap: 24px; +} + +.modal__close { + flex-shrink: 0; + width: 40px; + height: 40px; + display: flex; + align-items: center; + justify-content: center; + font-size: 20px; + color: var(--gray-600); + background: none; + border: none; + cursor: pointer; + transition: color var(--transition-fast); +} + +.modal__close:hover { + color: var(--text-primary); +} + +.modal__title { + font-family: var(--font-family-inter); + font-size: 24px; + font-weight: var(--fw-semibold); + line-height: 32px; + flex: 1; +} + +.modal__body { + padding: 24px 40px 40px; + display: flex; + flex-direction: column; + gap: 24px; + overflow-y: auto; + flex: 1; + /* Required for flex children to shrink below content height */ + min-height: 0; +} + +.modal__meta { + display: flex; + gap: 24px; + font-family: var(--font-family-inter); + font-size: var(--fs-small); + color: var(--gray-650); +} + +.modal__meta-item { + display: flex; + align-items: center; + gap: 8px; +} + +.modal__meta-item i { + color: var(--gray-600); +} + +.modal__description { + font-family: var(--font-family-inter); + font-size: var(--fs-base); + line-height: 24px; + color: var(--text-primary); +} + +.modal__description p + p { + margin-top: 16px; +} + +/* Modal Navigation */ +.modal__nav { + display: flex; + justify-content: space-between; + padding: 16px 40px; + border-top: 1px solid var(--gray-200); + background: var(--gray-100); +} + +.modal__nav-btn { + display: flex; + align-items: center; + gap: 8px; + font-family: var(--font-family-inter); + font-size: var(--fs-small); + font-weight: var(--fw-semibold); + color: var(--petroleum); + background: none; + border: none; + cursor: pointer; + padding: 8px 16px; + transition: color var(--transition-fast); +} + +.modal__nav-btn:hover { + color: var(--petroleum-800); +} + +.modal__nav-btn:disabled { + color: var(--gray-500); + cursor: not-allowed; +} + +.modal__nav-counter { + font-family: var(--font-family-inter); + font-size: var(--fs-small); + color: var(--gray-650); + display: flex; + align-items: center; +} + +@media (max-width: 640px) { + .modal { + margin: 0; + min-height: 100vh; + } + + .modal-overlay { + padding: 0; + } + + .modal__header { + padding: 24px 20px 0; + } + + .modal__body { + padding: 16px 20px 24px; + } + + .modal__nav { + padding: 12px 20px; + } +} diff --git a/docs/public/projects/deltag-aarhus/mocks/css/nav.css b/docs/public/projects/deltag-aarhus/mocks/css/nav.css new file mode 100644 index 0000000..dfb1891 --- /dev/null +++ b/docs/public/projects/deltag-aarhus/mocks/css/nav.css @@ -0,0 +1,153 @@ +/* Navigation — main site navigation bar with logo, links, search, and compact scroll variant */ + +.nav { + position: sticky; + /* Offset below the mock banner (28px tall) */ + top: 28px; + /* Above content, below modals (1000) */ + z-index: 100; + background: var(--white); + box-shadow: var(--shadow-nav); + padding: 18px 36px 24px; + display: flex; + justify-content: center; + transition: padding 0.3s ease; +} + +.nav__inner { + display: flex; + gap: 48px; + align-items: flex-start; + width: 100%; + max-width: var(--container-max); +} + +.nav__logo { + flex-shrink: 0; + display: flex; + align-items: center; + align-self: center; +} + +.nav__logo img { + transition: height 0.3s ease; +} + +.nav__logo svg { + height: 40px; + width: auto; +} + +.nav__right { + flex: 1; + display: flex; + flex-direction: column; + align-items: flex-end; + gap: 18px; + transition: gap 0.3s ease; +} + +.nav__sub-menu { + display: flex; + gap: 24px; + overflow: hidden; + max-height: 24px; + opacity: 1; + transition: max-height 0.3s ease, opacity 0.2s ease, margin 0.3s ease; +} + +/* Compact nav on scroll */ +.nav--compact { + padding: 8px 36px 12px; +} + +.nav--compact .nav__logo img { + height: 40px; +} + +.nav--compact .nav__inner { + align-items: center; +} + +.nav--compact .nav__right { + gap: 0; +} + +.nav--compact .nav__sub-menu { + max-height: 0; + opacity: 0; + margin: 0; +} + +.nav--compact .nav__link--active::after { + bottom: -19px; +} + +.nav__sub-link { + font-size: var(--fs-small); + color: var(--text-primary); + text-decoration: none; + padding-bottom: 3px; +} + +.nav__sub-link:hover { + color: var(--text-link); +} + +.nav__main-menu { + display: flex; + gap: 30px; + align-items: center; +} + +.nav__link { + font-size: 15px; + font-weight: var(--fw-bold); + color: var(--text-primary); + text-decoration: none; + position: relative; + padding-bottom: 4px; +} + +.nav__link:hover { + color: var(--petroleum); +} + +.nav__link--active { + color: var(--petroleum); +} + +.nav__link--active::after { + content: ""; + position: absolute; + /* Aligns indicator with bottom edge of full nav */ + bottom: -26px; + left: 0; + right: 0; + height: 5px; + background: var(--petroleum); +} + +.nav__divider { + width: 1px; + height: 18px; + background: var(--gray-300); +} + +.nav__search { + color: var(--petroleum); + font-size: 18px; + padding: 0; + display: flex; + align-items: center; +} + +@media (max-width: 640px) { + .nav__main-menu { + display: none; + } + + .nav__sub-menu { + display: none; + } +} diff --git a/docs/public/projects/deltag-aarhus/mocks/css/projects-cta.css b/docs/public/projects/deltag-aarhus/mocks/css/projects-cta.css new file mode 100644 index 0000000..4d1204f --- /dev/null +++ b/docs/public/projects/deltag-aarhus/mocks/css/projects-cta.css @@ -0,0 +1,77 @@ +/* Projects CTA — call-to-action section with background image and text card */ + +.projects-cta { + background-color: var(--blue-100); + background-size: cover; + background-position: center; + min-height: 500px; + display: flex; + align-items: center; + justify-content: center; + position: relative; + overflow: hidden; +} + +.projects-cta__inner { + display: flex; + align-items: center; + gap: 48px; + max-width: 1400px; + width: 100%; + padding: 48px 120px; +} + +.projects-cta__text-box { + background: var(--white); + border-radius: 6px; + padding: 60px 61px; + display: flex; + flex-direction: column; + gap: 22px; + max-width: 630px; + flex-shrink: 0; +} + +.projects-cta__label { + font-size: var(--fs-small); + font-weight: var(--fw-bold); +} + +.projects-cta__title { + font-size: 40px; + font-weight: var(--fw-bold); + line-height: 48px; +} + +.projects-cta__desc { + font-size: var(--fs-base); + line-height: 24px; +} + +.projects-cta__button { + display: inline-flex; + align-items: center; + justify-content: center; + background: var(--petroleum); + color: var(--white); + font-size: 15px; + padding: 12px 30px; + border-radius: 2px; + text-decoration: none; + letter-spacing: 0.5px; + width: 264px; + height: 48px; + transition: background var(--transition-fast); +} + +.projects-cta__button:hover { + background: var(--petroleum-800); + color: var(--white); +} + +@media (max-width: 960px) { + .projects-cta__inner { + flex-direction: column; + padding: 48px 24px; + } +} diff --git a/docs/public/projects/deltag-aarhus/mocks/css/related.css b/docs/public/projects/deltag-aarhus/mocks/css/related.css new file mode 100644 index 0000000..108747e --- /dev/null +++ b/docs/public/projects/deltag-aarhus/mocks/css/related.css @@ -0,0 +1,169 @@ +/* Related — related activities section with activity cards */ + +.related-section { + background: var(--gray-100); + padding: 56px 0; +} + +.related-section__title { + font-size: var(--fs-teaser); + font-weight: var(--fw-bold); + margin-bottom: 32px; +} + +.related-section__inner { + max-width: var(--container-max); + margin: 0 auto; + padding-inline: 116px; +} + +.related-section__grid { + display: flex; + gap: 20px; + flex-wrap: wrap; + max-width: var(--container-max); + margin: 0 auto; + padding-inline: 116px; +} + +/* Activity Card */ +.activity-card { + background: var(--white); + display: flex; + flex-direction: column; + width: 430px; + text-decoration: none; + color: var(--text-primary); + transition: box-shadow var(--transition-card-in); + position: relative; +} + +.activity-card:hover { + box-shadow: var(--shadow-card); + color: var(--text-primary); +} + +.activity-card__image { + height: 240px; + overflow: hidden; + position: relative; +} + +.activity-card__image img { + width: 100%; + height: 100%; + object-fit: cover; + transition: transform var(--transition-card-out); +} + +.activity-card:hover .activity-card__image img { + transform: scale(1.07); +} + +.activity-card__date-badge { + position: absolute; + bottom: 0; + left: 0; + background: var(--white); + width: 59px; + height: 70px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 3px; + padding: 15px 14px; +} + +.activity-card__date-day { + font-size: 18px; + font-weight: var(--fw-bold); + text-align: center; +} + +.activity-card__date-month { + font-size: var(--fs-small); + text-align: center; +} + +.activity-card__body { + padding: 32px 29px; + display: flex; + flex-direction: column; + gap: 20px; + flex: 1; +} + +.activity-card__type { + font-size: var(--fs-xs); + font-weight: var(--fw-bold); + color: var(--petroleum); + letter-spacing: 0.1px; +} + +.activity-card__title { + font-size: 20px; + font-weight: var(--fw-bold); + line-height: 26px; + letter-spacing: 0.2px; + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; +} + +.activity-card__details { + display: flex; + flex-direction: column; +} + +.activity-card__detail-row { + display: flex; + align-items: center; + gap: 13px; + padding: 10px 0; + border-bottom: 1px solid var(--gray-350); + font-size: var(--fs-small); +} + +.activity-card__detail-row:last-child { + border-bottom: none; +} + +.activity-card__detail-row i { + width: 25px; + text-align: center; + color: var(--petroleum); + font-size: 20px; +} + +.activity-card__arrow { + display: flex; + justify-content: flex-end; + color: var(--text-primary); + font-size: var(--fs-small); +} + +@media (max-width: 1200px) { + .related-section { + padding-inline: 40px; + } +} + +@media (max-width: 960px) { + .related-section__grid { + padding-left: 24px; + padding-right: 24px; + } + + .related-section__title { + padding-left: 24px; + } +} + +@media (max-width: 640px) { + .activity-card { + width: 100%; + } +} diff --git a/docs/public/projects/deltag-aarhus/mocks/css/statistics.css b/docs/public/projects/deltag-aarhus/mocks/css/statistics.css new file mode 100644 index 0000000..752decb --- /dev/null +++ b/docs/public/projects/deltag-aarhus/mocks/css/statistics.css @@ -0,0 +1,315 @@ +/* Statistics — charts section with bar charts, line charts, and category charts */ + +.statistics-section { + max-width: var(--container-max); + margin: 0 auto; + padding: 0 116px 48px; +} + +.statistics-section__heading { + font-size: var(--fs-teaser); + font-weight: var(--fw-bold); + margin-bottom: 24px; +} + +/* Line Chart */ +.line-chart { + display: flex; + gap: 12px; +} + +.line-chart__y-axis { + display: flex; + flex-direction: column; + justify-content: space-between; + font-family: var(--font-family-inter); + font-size: var(--fs-xs); + color: var(--gray-650); + text-align: right; + min-width: 30px; + padding-bottom: 28px; +} + +.line-chart__area { + flex: 1; + display: flex; + flex-direction: column; +} + +.line-chart__svg { + width: 100%; + height: 200px; +} + +.line-chart__x-axis { + display: flex; + justify-content: space-between; + font-family: var(--font-family-inter); + font-size: var(--fs-xs); + color: var(--gray-650); + padding-top: 8px; +} + +/* Statistics */ +.statistics { + max-width: none; + width: 100%; + margin: 0 0 48px; + padding: 40px; + border-radius: 8px; + border: 1px solid var(--border-default); + overflow: hidden; + display: flex; + flex-direction: column; + gap: 32px; +} + +.statistics:last-child { + margin-bottom: 0; +} + +.statistics__header { + display: flex; + flex-direction: column; + gap: 8px; +} + +.statistics__title { + font-family: var(--font-family-inter); + font-size: var(--fs-base); + font-weight: var(--fw-semibold); +} + +.statistics__subtitle { + font-family: var(--font-family-inter); + font-size: var(--fs-small); +} + +.statistics__chart { + display: flex; + gap: 16px; +} + +.statistics__y-label { + width: 20px; + display: flex; + align-items: center; + justify-content: center; +} + +.statistics__y-label span { + transform: rotate(-90deg); + white-space: nowrap; + font-family: var(--font-family-inter); + font-size: var(--fs-small); +} + +.statistics__y-axis { + width: 60px; + display: flex; + flex-direction: column; + justify-content: space-between; + height: 300px; +} + +.statistics__y-tick { + font-family: var(--font-family-inter); + font-size: var(--fs-small); + text-align: right; + height: 20px; + display: flex; + align-items: center; + justify-content: flex-end; +} + +.statistics__bars-wrapper { + flex: 1; + height: 300px; + position: relative; +} + +.statistics__grid-lines { + position: absolute; + inset: 0; + display: flex; + flex-direction: column; + justify-content: space-between; + pointer-events: none; +} + +.statistics__grid-line { + height: 1px; + background: var(--gray-200); +} + +.statistics__bars { + position: relative; + z-index: 1; + height: 100%; + display: flex; + justify-content: space-between; + align-items: flex-end; + padding: 0 20px; +} + +.statistics__bar-group { + display: flex; + flex-direction: column; + align-items: center; + justify-content: flex-end; + gap: 12px; + width: 80px; + height: 100%; +} + +.statistics__bar { + width: 48px; + background: var(--blue); + border-radius: 4px 4px 0 0; + transition: opacity var(--transition-fast); +} + +.statistics__bar:hover { + opacity: 0.8; +} + +.statistics__bar-label { + font-family: var(--font-family-inter); + font-size: var(--fs-small); + text-align: center; +} + +.statistics__x-label { + text-align: center; + font-family: var(--font-family-inter); + font-size: var(--fs-small); + padding-top: 16px; +} + +.statistics__footer { + display: flex; + justify-content: space-between; + align-items: center; + padding-top: 16px; +} + +.statistics__legend { + display: flex; + align-items: center; + gap: 8px; + font-family: var(--font-family-inter); + font-size: var(--fs-small); +} + +.statistics__legend-color { + width: 12px; + height: 12px; + border-radius: 2px; + background: var(--blue); +} + +.statistics__total { + font-family: var(--font-family-inter); + font-size: var(--fs-small); +} + +/* Category Chart */ +.category-chart { + display: flex; + flex-direction: column; + gap: 20px; +} + +.category-chart__row { + display: flex; + align-items: center; + gap: 16px; +} + +.category-chart__label { + font-family: var(--font-family-inter); + font-size: var(--fs-small); + font-weight: var(--fw-semibold); + width: 110px; + flex-shrink: 0; + text-align: right; +} + +.category-chart__bar-track { + flex: 1; + height: 32px; + background: var(--gray-100); + border-radius: 4px; + overflow: hidden; +} + +.category-chart__bar { + height: 100%; + background: var(--blue); + border-radius: 4px; + /* Slower than default for animated bar fill effect */ + transition: width 0.6s ease; +} + +.category-chart__bar--green { + background: var(--green); +} + +.category-chart__bar--petroleum { + background: var(--petroleum); +} + +.category-chart__bar--orange { + background: var(--orange); +} + +.category-chart__value { + font-family: var(--font-family-inter); + font-size: var(--fs-small); + font-weight: var(--fw-semibold); + width: 40px; + flex-shrink: 0; +} + +.category-chart__legend { + display: flex; + gap: 20px; + font-family: var(--font-family-inter); + font-size: var(--fs-small); +} + +.category-chart__legend-item { + display: flex; + align-items: center; + gap: 6px; +} + +.category-chart__legend-color { + display: inline-block; + width: 12px; + height: 12px; + border-radius: 2px; + background: var(--blue); +} + +.category-chart__legend-color--green { + background: var(--green); +} + +.category-chart__legend-color--petroleum { + background: var(--petroleum); +} + +.category-chart__legend-color--orange { + background: var(--orange); +} + +@media (max-width: 1200px) { + .statistics-section { + padding-inline: 40px; + } + + .statistics { + margin-left: 0; + } +} diff --git a/docs/public/projects/deltag-aarhus/mocks/css/tokens.css b/docs/public/projects/deltag-aarhus/mocks/css/tokens.css new file mode 100644 index 0000000..588599f --- /dev/null +++ b/docs/public/projects/deltag-aarhus/mocks/css/tokens.css @@ -0,0 +1,111 @@ +/* Design tokens from deltag.aarhus.dk design system. + This file contains only custom properties — no component styles. + Inter is the UI font (cards, modals, stats, pagination). + The base font-family (Arial stack) is used for body/prose text. + Breakpoints: 1200px (tablet), 960px (small tablet), 640px (mobile). */ + +:root { + /* Brand */ + --petroleum: #008486; + --petroleum-100: #e5eef0; + --petroleum-200: #cfe0e2; + --petroleum-300: #b2dada; + --petroleum-400: #8fcfcf; + --petroleum-800: #3d6d6d; + --petroleum-900: #2a4a4a; + --petroleum-muted: #467176; + + /* Grayscale */ + --white: #fff; + --gray-50: #f6f6f6; + --gray-100: #f5f5f5; + --gray-200: #eaeaea; + --gray-300: #e6e6e6; + --gray-350: #dfdfdf; + --gray-400: #d6d6d6; + --gray-500: #9d9d9d; + --gray-600: #858585; + --gray-650: #666; + --gray-700: #525252; + --gray-800: #444; + --gray-900: #333; + --black: #1a1a1a; + + /* Accent */ + --pink: #ee0043; + --blue: #3661d8; + --blue-50: #eff6ff; + --blue-100: #ebeffb; + --blue-200: #bfdbfe; + --purple: #673ab7; + --green: #008850; + --yellow: #ffe13d; + --yellow-50: #fffbeb; + --yellow-100: #fef3c7; + --orange: #ff5f31; + --red: #d32f2f; + + /* Neutral Warm */ + --peach-100: #f7f0e8; + --peach-200: #e8dfd4; + --peach-700: #7a6f64; + + /* Semantic */ + --text-primary: var(--gray-900); + --text-secondary: var(--gray-700); + --text-muted: var(--gray-500); + --text-inverse: var(--white); + --text-link: var(--petroleum); + --text-link-hover: var(--petroleum-800); + + --bg-primary: var(--white); + --bg-secondary: var(--gray-50); + --bg-tertiary: var(--gray-200); + + --border-default: var(--gray-300); + --border-strong: var(--gray-900); + --border-subtle: var(--gray-200); + + /* Typography */ + --font-family: arial, -apple-system, blinkmacsystemfont, "Segoe UI", roboto, + "Helvetica Neue", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", + "Segoe UI Symbol"; + --font-family-inter: "Inter", var(--font-family); + + --fs-display: 4rem; + --fs-h1: 2.2rem; + --fs-teaser: 1.625rem; + --fs-h2: 1.4rem; + --fs-lead: 1.3rem; + --fs-large: 1.25rem; + --fs-h3: 1.2rem; + --fs-h4: 1.1rem; + --fs-base: 1rem; + --fs-small: 0.875rem; + --fs-xs: 0.75rem; + + --fw-regular: 400; + --fw-semibold: 600; + --fw-bold: 700; + --fw-black: 900; + + --lh-body: 1.5; + --lh-heading: 1.4; + + /* Spacing */ + --spacer: 1rem; + + /* Shadows */ + --shadow-card: 0 0.25rem 1rem rgb(0 0 0 / 16%); + --shadow-nav: 0 2px 10px rgb(0 0 0 / 30%); + --shadow-medium: 0 0 2px rgb(0 0 0 / 2%), 1px 3px 16px rgb(0 0 0 / 8%); + + /* Layout */ + --container-max: 1352px; + --container-padding: 124px; + + /* Transitions */ + --transition-fast: 0.2s ease-in; + --transition-card-in: 200ms ease; + --transition-card-out: 400ms ease; +} diff --git a/docs/public/projects/deltag-aarhus/mocks/css/variant.css b/docs/public/projects/deltag-aarhus/mocks/css/variant.css new file mode 100644 index 0000000..8060b83 --- /dev/null +++ b/docs/public/projects/deltag-aarhus/mocks/css/variant.css @@ -0,0 +1,69 @@ +/* Variant — conditional styles toggled by body.variant--open / body.variant--closed */ + +/* In the open variant the decision banner is hidden, so the hearing header + overlaps the hero image directly — matching the closed variant's visual weight. */ +body.variant--open .hearing-header { + margin-top: -50px; +} + +/* Tooltip on disabled submit button (closed variant) */ +.btn-primary-wrapper { + position: relative; + margin-left: auto; +} + +.btn-primary__tooltip { + display: none; + position: absolute; + bottom: calc(100% + 10px); + right: 0; + background: var(--gray-800); + color: var(--white); + font-family: var(--font-family-inter); + font-size: var(--fs-xs); + line-height: 1.4; + padding: 10px 14px; + border-radius: 4px; + white-space: nowrap; + pointer-events: none; + z-index: 10; +} + +.btn-primary__tooltip::after { + content: ""; + position: absolute; + top: 100%; + right: 24px; + border: 6px solid transparent; + border-top-color: var(--gray-800); +} + +.btn-primary:disabled { + background: var(--gray-400); + border-color: var(--gray-400); + color: var(--gray-600); + cursor: not-allowed; +} + +.btn-primary:disabled:hover { + background: var(--gray-400); + color: var(--gray-600); +} + +.btn-primary:disabled:hover + .btn-primary__tooltip, +.btn-primary:disabled:focus + .btn-primary__tooltip { + display: block; +} + +@media (max-width: 640px) { + .btn-primary-wrapper { + margin-left: 0; + width: 100%; + } + + .btn-primary__tooltip { + white-space: normal; + width: 260px; + right: 0; + } +} diff --git a/docs/public/projects/deltag-aarhus/mocks/hero-moeller.png b/docs/public/projects/deltag-aarhus/mocks/hero-moeller.png new file mode 100644 index 0000000..9ce7ff0 Binary files /dev/null and b/docs/public/projects/deltag-aarhus/mocks/hero-moeller.png differ diff --git a/docs/public/projects/deltag-aarhus/mocks/index.html b/docs/public/projects/deltag-aarhus/mocks/index.html new file mode 100644 index 0000000..64965cf --- /dev/null +++ b/docs/public/projects/deltag-aarhus/mocks/index.html @@ -0,0 +1,718 @@ + + +
+ + +
+ Planen udlægger området til tekniske anlæg og giver mulighed for opstilling af tre vindmøller med en totalhøjde på op til 150 meter samt tilhørende arbejdsarealer, veje og nettilslutningsanlæg.
+HøringenEn høring er en periode hvor borgere, organisationer og myndigheder kan komme med kommentarer og forslag til et bestemt planforslag, før det vedtages endeligt. Læs mere om høringer vedrører Forslag til Lokalplan nr. 1237 med tilhørende miljøvurderingsrapport for opstilling af vindmøller ved Vosnæs nord for Aarhus. Bemærk at høringssvar først gennemgås efter endt høringsfrist.
+Aarhus Kommune har udarbejdet forslag til lokalplan for Vosnæs-området samt tillæg nr. 169 til Kommuneplan 2017Kommuneplanen er kommunens overordnede plan for arealanvendelse de næste 12 år. Den sætter rammerne for hvad der må bygges hvor. Læs mere om kommuneplanen. Der er gennemført en samlet miljøvurderingEn miljøvurdering er en systematisk vurdering af, hvordan et planforslag eller projekt påvirker miljøet — fx natur, støj, landskab og menneskers sundhed. Den er lovpligtig ved væsentlig miljøpåvirkning. Læs mere om miljøvurdering for alle planer og projekter i området.
+Planerne kan ses på Aarhus Lokalplanportal samt fysisk på Dokk1 Hovedbibliotek fra den 5. juni 2025. Lokalplanen udlægger området til tekniske anlægTekniske anlæg dækker over installationer som vindmøller, solcelleanlæg, transformerstationer og lignende infrastruktur, der er nødvendig for energiforsyning og teknisk drift. Læs mere om tekniske anlæg og muliggør opstilling af tre vindmøller med en totalhøjde på op til 150 meter.
+Indkomne høringssvar over tid
+Antal svar per uge i høringsperioden (5. jun – 14. aug 2025)
+Fordeling på kategorier
+Antal høringssvar fordelt på kategori
+Geografisk fordeling af høringssvar
+Kortet viser hvor høringssvarene kommer fra. Større cirkler angiver flere svar fra området.
+På aarhus.dk har vi samlet viden om vindmølleprojekter og lokalplanprocessen. Se bl.a. disse sider.
+ Vindenergi i Aarhus Kommune + Hvad er en lokalplan + Miljøvurdering af planer og projekter +Se hvilke projekter der aktuelt er igang og som du kan bidrage til som borger i Aarhus Kommune
+ Se igangværende projekter +' + item.description + '
' + + ''; + + if (isOpen) { + var likeBtn = card.querySelector(".horingssvar-card__like-btn"); + likeBtn.addEventListener("click", function(e) { + e.stopPropagation(); + item.likes++; + likeBtn.querySelector(".horingssvar-card__like-count").textContent = DM.formatNumber(item.likes); + likeBtn.classList.add("horingssvar-card__like-btn--liked"); + likeBtn.disabled = true; + }); + } + + card.addEventListener("click", function() { DM.openModal(index); }); + card.addEventListener("keydown", function(e) { + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + DM.openModal(index); + } + }); + + return card; +} + +DM.renderGrid = function() { + var state = DM.state; + var grid = document.getElementById("horingssvar-grid"); + var countEl = document.getElementById("horingssvar-count"); + var paginationCount = document.getElementById("pagination-count"); + var showMoreBtn = document.getElementById("show-all-btn"); + + state.filteredData = sortData(filterData(DM.horingssvarData, state.currentCategory), state.currentSort); + + grid.innerHTML = ""; + var shown = Math.min(state.visibleCount, state.filteredData.length); + var displayData = state.filteredData.slice(0, shown); + + displayData.forEach(function(item, index) { + grid.appendChild(createCard(item, index)); + }); + + countEl.textContent = state.filteredData.length; + paginationCount.textContent = "Viser 1 - " + shown + " af " + state.filteredData.length; + + if (shown >= state.filteredData.length) { + showMoreBtn.style.display = "none"; + } else { + showMoreBtn.textContent = "Vis flere"; + showMoreBtn.style.display = ""; + } +}; diff --git a/docs/public/projects/deltag-aarhus/mocks/js/main.js b/docs/public/projects/deltag-aarhus/mocks/js/main.js new file mode 100644 index 0000000..d93ed89 --- /dev/null +++ b/docs/public/projects/deltag-aarhus/mocks/js/main.js @@ -0,0 +1,83 @@ +window.DeltagMock = window.DeltagMock || {}; +var DM = window.DeltagMock; + +/* ========================================================================== + Initialization + ========================================================================== */ + +function init() { + var state = DM.state; + var overlay = document.getElementById("modal-overlay"); + + DM.renderGrid(); + DM.initDropdowns(); + + // Show More + document.getElementById("show-all-btn").addEventListener("click", function() { + state.visibleCount += state.ITEMS_PER_PAGE; + DM.renderGrid(); + }); + + // Modal close + overlay.querySelector(".modal__close").addEventListener("click", DM.closeModal); + + overlay.addEventListener("click", function(e) { + if (e.target === overlay) DM.closeModal(); + }); + + // Modal navigation + document.getElementById("modal-prev").addEventListener("click", function() { DM.navigateModal(-1); }); + document.getElementById("modal-next").addEventListener("click", function() { DM.navigateModal(1); }); + + // Keyboard + document.addEventListener("keydown", function(e) { + if (state.currentModalIndex === -1) return; + + switch (e.key) { + case "Escape": + DM.closeModal(); + break; + case "ArrowLeft": + DM.navigateModal(-1); + break; + case "ArrowRight": + DM.navigateModal(1); + break; + } + }); + + // Focus trap in modal + DM.initFocusTrap(); + + // Close dropdowns on outside click + document.addEventListener("click", function() { + document.querySelectorAll(".dropdown__menu--open").forEach(function(m) { + m.classList.remove("dropdown__menu--open"); + }); + document.querySelectorAll('.dropdown__button[aria-expanded="true"]').forEach(function(b) { + b.setAttribute("aria-expanded", "false"); + }); + }); + + // Deep-link: open modal from URL hash + var hash = window.location.hash; + if (hash.indexOf("#svar-") === 0) { + var id = parseInt(hash.replace("#svar-", ""), 10); + var index = state.filteredData.findIndex(function(item) { return item.id === id; }); + if (index !== -1) { + DM.openModal(index); + } + } +} + +document.addEventListener("DOMContentLoaded", function() { + init(); + DM.initMap(); + DM.initMaterialModal(); + DM.initDecisionModal(); + DM.initGlossary(); + DM.initCompactNav(); + DM.initVariant(); + DM.initMitIDModal(); + DM.initSubmissionModal(); +}); diff --git a/docs/public/projects/deltag-aarhus/mocks/js/map.js b/docs/public/projects/deltag-aarhus/mocks/js/map.js new file mode 100644 index 0000000..85e9700 --- /dev/null +++ b/docs/public/projects/deltag-aarhus/mocks/js/map.js @@ -0,0 +1,53 @@ +window.DeltagMock = window.DeltagMock || {}; +var DM = window.DeltagMock; + +/* ========================================================================== + Map + ========================================================================== */ + +DM.initMap = function() { + var map = L.map("map", { scrollWheelZoom: false }).setView([56.18, 10.15], 12); + + L.tileLayer("https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png", { + attribution: '© OpenStreetMap © CARTO', + subdomains: "abcd", + maxZoom: 20, + }).addTo(map); + + /* Hearing response locations on land around Skødstrup, Løgten and Aarhus. + All points placed well inland to avoid the bay. */ + var responseLocations = [ + { lat: 56.209, lng: 10.148, count: 45, label: "Skødstrup" }, + { lat: 56.192, lng: 10.175, count: 32, label: "Løgten" }, + { lat: 56.155, lng: 10.210, count: 28, label: "Aarhus C" }, + { lat: 56.178, lng: 10.120, count: 22, label: "Lystrup" }, + { lat: 56.168, lng: 10.195, count: 18, label: "Risskov" }, + { lat: 56.218, lng: 10.105, count: 15, label: "Hjortshøj" }, + { lat: 56.148, lng: 10.125, count: 12, label: "Brabrand" }, + { lat: 56.195, lng: 10.095, count: 10, label: "Trige" }, + { lat: 56.162, lng: 10.165, count: 8, label: "Vejlby" }, + { lat: 56.140, lng: 10.165, count: 6, label: "Viby" }, + { lat: 56.175, lng: 10.080, count: 4, label: "Sabro" }, + ]; + + var maxCount = Math.max.apply(null, responseLocations.map(function(l) { return l.count; })); + + responseLocations.forEach(function(loc) { + var ratio = loc.count / maxCount; + var radius = 20 + ratio * 60; + var opacity = 0.25 + ratio * 0.4; + + L.circleMarker([loc.lat, loc.lng], { + radius: radius, + fillColor: "#3661d8", + color: "#3661d8", + weight: 1, + fillOpacity: opacity, + opacity: 0.6, + }) + .addTo(map) + .bindPopup( + "" + loc.label + "" + p + "
"; }) + .join(""); + + // Comments + var commentsSection = document.getElementById("modal-comments"); + var commentsTitle = commentsSection.querySelector(".modal__comments-title"); + commentsSection.innerHTML = ""; + commentsSection.appendChild(commentsTitle); + + if (item.commentsList && item.commentsList.length > 0) { + var visibleComments = item.commentsList.slice(0, state.commentsVisible); + visibleComments.forEach(function(comment) { + var commentEl = document.createElement("div"); + commentEl.className = "modal__comment"; + commentEl.innerHTML = + '' + + '' + comment.date + '' + + '' + comment.text + '
'; + commentsSection.appendChild(commentEl); + }); + + var remaining = item.commentsList.length - state.commentsVisible; + if (remaining > 0) { + var showMoreBtn = document.createElement("button"); + showMoreBtn.className = "modal__comments-show-more"; + showMoreBtn.textContent = "Vis flere kommentarer (" + remaining + " mere)"; + showMoreBtn.addEventListener("click", function() { + /* Progressive disclosure: load next batch on click */ + state.commentsVisible += state.COMMENTS_PER_PAGE; + DM.updateModalContent(); + }); + commentsSection.appendChild(showMoreBtn); + } + } + + /* Comment form — only shown in the open variant */ + if (state.variant === "open") { + var commentForm = document.createElement("form"); + commentForm.className = "modal__comment-form"; + commentForm.innerHTML = + '' + + '' + + ''; + commentsSection.appendChild(commentForm); + + commentForm.addEventListener("submit", function(e) { + e.preventDefault(); + var textarea = commentForm.querySelector("textarea"); + var text = textarea.value.trim(); + if (!text) return; + + item.commentsList.push({ + author: "Maria Jensen (dig)", + date: "I dag", + text: text + }); + item.comments++; + textarea.value = ""; + DM.updateModalContent(); + }); + } + + // Navigation + var prevBtn = document.getElementById("modal-prev"); + var nextBtn = document.getElementById("modal-next"); + var counter = document.getElementById("modal-counter"); + + prevBtn.disabled = state.currentModalIndex === 0; + nextBtn.disabled = state.currentModalIndex === state.filteredData.length - 1; + counter.textContent = (state.currentModalIndex + 1) + " af " + state.filteredData.length; +}; + +DM.navigateModal = function(direction) { + var state = DM.state; + var newIndex = state.currentModalIndex + direction; + if (newIndex < 0 || newIndex >= state.filteredData.length) return; + state.currentModalIndex = newIndex; + /* Reset to first page when switching to a different item */ + state.commentsVisible = state.COMMENTS_PER_PAGE; + DM.updateModalContent(); + window.history.replaceState(null, "", "#svar-" + state.filteredData[state.currentModalIndex].id); +}; diff --git a/docs/public/projects/deltag-aarhus/mocks/js/modal-material.js b/docs/public/projects/deltag-aarhus/mocks/js/modal-material.js new file mode 100644 index 0000000..bc74540 --- /dev/null +++ b/docs/public/projects/deltag-aarhus/mocks/js/modal-material.js @@ -0,0 +1,16 @@ +window.DeltagMock = window.DeltagMock || {}; +var DM = window.DeltagMock; + +/* ========================================================================== + Material Document Modal + ========================================================================== */ + +DM.initMaterialModal = function() { + var controller = DM.createModalController("material-modal-overlay", "material-modal-close"); + var trigger = document.getElementById("material-lokalplan"); + + trigger.addEventListener("click", function(e) { + e.preventDefault(); + controller.open(); + }); +}; diff --git a/docs/public/projects/deltag-aarhus/mocks/js/modal-mitid.js b/docs/public/projects/deltag-aarhus/mocks/js/modal-mitid.js new file mode 100644 index 0000000..2aa19f5 --- /dev/null +++ b/docs/public/projects/deltag-aarhus/mocks/js/modal-mitid.js @@ -0,0 +1,20 @@ +window.DeltagMock = window.DeltagMock || {}; +var DM = window.DeltagMock; + +/* ========================================================================== + MitID Login Modal (mock) + ========================================================================== */ + +DM.initMitIDModal = function() { + var controller = DM.createModalController("mitid-modal-overlay", "mitid-modal-close"); + + DM.openMitIDModal = controller.open; + + document.getElementById("mitid-approve-btn").addEventListener("click", function() { + controller.close(); + /* Small delay so the close animation completes before opening the next modal */ + setTimeout(function() { + if (DM.openSubmissionModal) DM.openSubmissionModal(); + }, 150); + }); +}; diff --git a/docs/public/projects/deltag-aarhus/mocks/js/modal-submission.js b/docs/public/projects/deltag-aarhus/mocks/js/modal-submission.js new file mode 100644 index 0000000..f5979df --- /dev/null +++ b/docs/public/projects/deltag-aarhus/mocks/js/modal-submission.js @@ -0,0 +1,33 @@ +window.DeltagMock = window.DeltagMock || {}; +var DM = window.DeltagMock; + +/* ========================================================================== + Høringssvar Submission Modal + ========================================================================== */ + +DM.initSubmissionModal = function() { + var controller = DM.createModalController("submission-modal-overlay", "submission-modal-close"); + var form = document.getElementById("submission-form"); + var modalBody = form.parentElement; + + DM.openSubmissionModal = controller.open; + + form.addEventListener("submit", function(e) { + e.preventDefault(); + + /* Show success state inside the modal instead of alert */ + modalBody.innerHTML = + 'Dit høringssvar er modtaget og vil indgå i den politiske behandling af Lokalplan nr. 1237. Du modtager en bekræftelse på e-mail.
' + + 'Dette er en mock — intet høringssvar er reelt indsendt.
' + + '
Kommentarer
+ +