commit 5f9e64e9f49a079ea92fc8f2ae94edc4430a7b5e Author: Jonas Weismueller Date: Mon Jul 13 22:12:02 2026 +0200 feat: neue Website mit Docker-Deployment diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..eb86f58 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,8 @@ +.git +.gitea +.DS_Store +README.md +package.json +server.mjs +node_modules +npm-debug.log* diff --git a/.gitea/workflows/docker.yml b/.gitea/workflows/docker.yml new file mode 100644 index 0000000..1f22368 --- /dev/null +++ b/.gitea/workflows/docker.yml @@ -0,0 +1,48 @@ +name: Docker-Image bauen + +on: + push: + branches: + - main + workflow_dispatch: + +env: + REGISTRY: git.servercentral.org + IMAGE: git.servercentral.org/jonas/hardtschule-karlsruhe.de + +jobs: + build-and-push: + name: Image bauen und veröffentlichen + runs-on: ubuntu-latest + permissions: + contents: read + + steps: + - name: Repository auschecken + uses: actions/checkout@v4 + + - name: An der Container-Registry anmelden + env: + REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }} + REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }} + run: | + test -n "$REGISTRY_USERNAME" || (echo "Secret REGISTRY_USERNAME fehlt" && exit 1) + test -n "$REGISTRY_TOKEN" || (echo "Secret REGISTRY_TOKEN fehlt" && exit 1) + printf '%s' "$REGISTRY_TOKEN" | docker login "$REGISTRY" --username "$REGISTRY_USERNAME" --password-stdin + + - name: Docker-Image bauen + run: | + docker build --pull \ + --label "org.opencontainers.image.revision=${{ gitea.sha }}" \ + --tag "$IMAGE:latest" \ + --tag "$IMAGE:${{ gitea.sha }}" \ + . + + - name: Docker-Image veröffentlichen + run: | + docker push "$IMAGE:latest" + docker push "$IMAGE:${{ gitea.sha }}" + + - name: Von der Container-Registry abmelden + if: ${{ always() }} + run: docker logout "$REGISTRY" diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..8073f20 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,14 @@ +FROM nginx:alpine + +LABEL org.opencontainers.image.title="Hardtschule Karlsruhe" +LABEL org.opencontainers.image.description="Statische Website der Hardtschule Karlsruhe" +LABEL org.opencontainers.image.source="https://git.servercentral.org/jonas/hardtschule-karlsruhe.de" + +COPY nginx.conf /etc/nginx/conf.d/default.conf +COPY index.html impressum.html datenschutz.html styles.css script.js /usr/share/nginx/html/ +COPY public/ /usr/share/nginx/html/public/ + +EXPOSE 80 + +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD wget -q --spider http://127.0.0.1/healthz || exit 1 diff --git a/README.md b/README.md new file mode 100644 index 0000000..5de4b28 --- /dev/null +++ b/README.md @@ -0,0 +1,67 @@ +# Neue Website der Hardtschule Karlsruhe + +Ein eigenständiger, responsiver Website-Prototyp auf Basis öffentlich auffindbarer Informationen der bisherigen Schulwebsite, des Webarchivs und der Stadt Karlsruhe. + +## Lokal ansehen + +```sh +npm run dev +``` + +Danach ist die Seite unter `http://127.0.0.1:4173` erreichbar. + +## Mit Docker betreiben + +Das veröffentlichte Image kann direkt aus der Gitea-Container-Registry gestartet werden: + +```sh +docker run -d \ + --name hardtschule-website \ + --restart unless-stopped \ + -p 8080:80 \ + git.servercentral.org/jonas/hardtschule-karlsruhe.de:latest +``` + +Die Website ist anschließend unter `http://localhost:8080` erreichbar. Alternativ genügt mit der enthaltenen Compose-Datei: + +```sh +docker compose up -d +``` + +Falls das Gitea-Paket nicht öffentlich ist, muss auf dem Zielsystem zuvor einmal `docker login git.servercentral.org` ausgeführt werden. + +### Image lokal bauen + +```sh +docker build -t hardtschule-website . +docker run --rm -p 8080:80 hardtschule-website +``` + +### Automatischer Build in Gitea + +Der Workflow unter `.gitea/workflows/docker.yml` baut bei jedem Push auf `main` zwei Tags: + +- `git.servercentral.org/jonas/hardtschule-karlsruhe.de:latest` +- `git.servercentral.org/jonas/hardtschule-karlsruhe.de:` + +Damit der Workflow das Image veröffentlichen kann: + +1. Repository-Actions und einen Runner mit dem Label `ubuntu-latest` aktivieren. +2. In Gitea einen Personal Access Token mit Schreibrecht für Pakete erstellen. +3. Unter **Repository → Einstellungen → Actions → Secrets** die Secrets `REGISTRY_USERNAME` und `REGISTRY_TOKEN` hinterlegen. + +Der unveränderliche Commit-Tag erlaubt bei Bedarf ein gezieltes Rollback. `latest` zeigt immer auf den aktuellen Stand von `main`. + +## Inhaltliche Quellen + +- bisherige Website und Webarchiv der Hardtschule Karlsruhe +- Stadt Karlsruhe: Hardtschule – Brandschutz und WC-Sanierung +- Stadt Karlsruhe: Städtischer Schülerhort an der Hardtschule +- Werkraum Karlsruhe: Theaterprojekte 2023/24 + +## Vor einer Veröffentlichung + +- aktuelle Termine, Materiallisten und Pläne ergänzen +- Kontaktangaben und Zuständigkeiten von der Schule bestätigen lassen +- Impressum und Datenschutz an Hosting und tatsächliche Dienste anpassen +- Nutzungsfreigabe für Fotos dokumentieren (Fotos im Prototyp: Dirk Altenkirch / Stadt Karlsruhe) diff --git a/compose.yml b/compose.yml new file mode 100644 index 0000000..6b1ef5e --- /dev/null +++ b/compose.yml @@ -0,0 +1,7 @@ +services: + website: + image: git.servercentral.org/jonas/hardtschule-karlsruhe.de:latest + container_name: hardtschule-website + restart: unless-stopped + ports: + - "8080:80" diff --git a/datenschutz.html b/datenschutz.html new file mode 100644 index 0000000..407afaf --- /dev/null +++ b/datenschutz.html @@ -0,0 +1,38 @@ + + + + + + + Datenschutz · Hardtschule Karlsruhe + + + + +
+ +
+ + diff --git a/impressum.html b/impressum.html new file mode 100644 index 0000000..13168cf --- /dev/null +++ b/impressum.html @@ -0,0 +1,38 @@ + + + + + + + Impressum · Hardtschule Karlsruhe + + + + +
+ +
+ + diff --git a/index.html b/index.html new file mode 100644 index 0000000..6ee9675 --- /dev/null +++ b/index.html @@ -0,0 +1,531 @@ + + + + + + + + Hardtschule Karlsruhe · Bewegte Grundschule + + + + + + + + + +
+
+ Grundschule in Karlsruhe-Mühlburg + + + Sekretariat: 0721 133-4686 + +
+
+ + + +
+
+ +
+
+

Willkommen an der Hardtschule

+

Bewegt lernen.
Gemeinsam wachsen.

+

+ Eine lebendige Grundschule in Mühlburg, an der Kinder neugierig lernen, Verantwortung übernehmen und sich wohlfühlen können. +

+ +
+ Bewegte Grundschule + Soziales Lernen + Deutschförderung +
+
+ +
+
+ Historischer Anbau der Hardtschule mit gelber Backsteinfassade + Foto: Dirk Altenkirch / Stadt Karlsruhe +
+ + +
+
+ +
+ +
+
+
+
+

Schnell gefunden

+

Was brauchen Sie gerade?

+
+

Die wichtigsten Wege für Familien – ohne langes Suchen.

+
+
+ + + + + FerienTermine der Stadt Karlsruhe + + + + + BetreuungStädtischer Schülerhort + + + + + Fehlzeit meldenSekretariat & Anrufbeantworter + + +
+
+
+ +
+
+
+

Was uns ausmacht

+

Eine Schule, die Kinder ganzheitlich stärkt

+

Wissen, Bewegung, Sprache und ein respektvolles Miteinander gehören an der Hardtschule zusammen.

+
+ +
+
+
+ 01 +

Lernen in Bewegung

+

Bewegungszeiten, bewegtes Lernen und abwechslungsreiche Pausen bringen Körper und Kopf in Schwung.

+
Seit 2010zertifizierte Grundschule mit sport- und bewegungserzieherischem Schwerpunkt
+ +
+ +
+
+ 02 +

Stark miteinander

+

Klassenrat, Schüler*innenparlament und soziale Lernzeiten geben Kindern Stimme, Halt und Verantwortung.

+
Seit 2023verankert ein Sozialcurriculum die gemeinsame Präventionsarbeit im Schulalltag
+ +
+ +
+
+ 03 +

Sprache öffnet Türen

+

In der Vorbereitungsklasse und der nachgehenden Förderung bekommen Kinder Zeit und Raum für Deutsch.

+
VKL & Förderungfür einen sicheren Einstieg in Unterricht, Freundschaften und den Schulalltag
+ +
+
+
+
+ +
+
+
+ Seitenansicht des denkmalgeschützten Anbaus der Hardtschule + Nahansicht der historischen Backsteinfassade + Historischer Charakter,
modern weitergedacht.
+
+ +
+

Unser Ort

+

Ein Schulhaus mit Geschichte und Zukunft

+

Die Hardtschule prägt Mühlburg seit 1847. Hinter der historischen Fassade entsteht jeden Tag Neues: Ideen, Freundschaften und mutige erste Schritte.

+
+
1847erbaut in Mühlburg
+
2020denkmalgerecht saniert
+
direkt nebenanCarl-Benz-Halle für Sport & Feste
+
+

Zum Schulgelände gehören Klassenzimmer, Lesezimmer, Schülerhort, der Schulhof und die „Grüne Insel“ mit Spielgeräten.

+ + Fotos: Dirk Altenkirch / Stadt Karlsruhe +
+
+
+ +
+
+
+
+

Schulleben

+

Neugier sieht jeden Tag anders aus

+
+

Werkstatt, Theater, Bewegung oder Technik: Kinder lernen besonders gut, wenn sie selbst ausprobieren und gestalten dürfen.

+
+ +
+
+ +
+ +

Ein Fest für alle Buchstaben

+

Beim Buchstabenfest wird aus ersten Zeichen eine ganze Welt voller Wörter.

+
+
+ +
+ +
+ +

Tüfteln, bauen, Roboter steuern

+

Technik wird spannend, wenn eigene Ideen laufen lernen.

+
+
+ +
+ +
+ +

Druckwerkstatt zum Anfassen

+

Material, Farbe und Handwerk machen Geschichte begreifbar.

+
+
+ +
+
+ +

Kopf an. Schuhe an. Los!

+

Bewegung findet nicht nur im Sportunterricht statt – sondern auch beim Lernen, in den Pausen und bei gemeinsamen Aktionen.

+ +
+ +
+
+
+
+ +
+
+
+

Gemeinschaft

+

Viele Menschen. Eine Schule.

+

Kinder, Familien, Kollegium und Partner gestalten die Hardtschule gemeinsam.

+
+ +
+
+ +

Kinder reden mit

+

Im Klassenrat und Schüler*innenparlament werden Ideen besprochen, Verantwortung geteilt und Lösungen gefunden.

+ +
+
+ +

Beratung, die da ist

+

Die Schulsozialarbeit unterstützt Kinder, Eltern und Lehrkräfte – freiwillig, vertraulich und kostenlos.

+ +
+
+ +

Engagement, das ankommt

+

Der Förderverein ermöglicht Pausenobst, Bücher, Spielgeräte, Theaterbesuche und gemeinsame Erlebnisse.

+ +
+
+ +
+ +

„Zusammen arbeiten, zusammen leben und zusammen lernen.“

+ Aus dem sozialen Leitbild der Hardtschule +
+
+
+ +
+
+
+

Für Familien

+

Alles Wichtige.
Einfach erklärt.

+

Vom ersten Schultag bis zur Betreuung: Hier finden Sie die häufigsten Themen auf einen Blick.

+
+ +
+ Direkt mit uns sprechen + 0721 133-4686 +
+
+
+ +
+
+ 01Mein Kind kommt in die Schule +
+

Für zukünftige Erstklässler*innen bündelt die Schule Informationen zu Anmeldung, Kennenlernen, Einschulung und dem Start in Klasse 1.

+ +
+
+
+ 02Material, Pläne & Downloads +
+

Materiallisten werden nach Klasse und Schuljahr geordnet. Stunden-, AG- und Ferienpläne erhalten einen eigenen, schnell auffindbaren Downloadbereich.

+ +
+
+
+ 03Betreuung nach dem Unterricht +
+

Der städtische Schülerhort befindet sich direkt an der Hardtschule. Verbindliche Angaben zu Angebot und Anmeldung stellt die Stadt Karlsruhe bereit.

+ Zur Hort-Seite +
+
+
+ 04Fehlzeiten & Beurlaubung +
+

Bitte melden Sie eine Fehlzeit möglichst früh über den mit der Klasse vereinbarten Weg. Das Sekretariat und der Anrufbeantworter sind unter 0721 133-4686 erreichbar.

+ Sekretariat anrufen +
+
+
+ 05Unterstützung & Beratung +
+

Schulsozialarbeit und Beratung unterstützen bei schulischen, persönlichen und familiären Anliegen. Gespräche sind vertraulich und kostenlos.

+ +
+
+
+
+
+ +
+
+
+

Kontakt & Anfahrt

+

Wir sind gern für Sie da.

+

Sie haben eine Frage? Rufen Sie an oder schreiben Sie uns. Bei einem Besuch melden Sie sich bitte zuerst im Sekretariat.

+
+
+ +

Hardtschule Karlsruhe
Hardtstraße 3
76185 Karlsruhe

+
+
+ +

Sekretariat
0721 133-4686
Anrufbeantworter ist geschaltet

+
+
+ +

Öffnungszeiten
Mo–Do, 7:30–11:30 Uhr
Freitags ist das Sekretariat nicht besetzt.

+
+ +
+
+ +
+ + +
+
+
+
+ + + + +
+ + +

+
+
+
+
+ + diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..3a0dd51 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,50 @@ +server { + listen 80 default_server; + listen [::]:80 default_server; + server_name _; + + root /usr/share/nginx/html; + index index.html; + charset utf-8; + server_tokens off; + + add_header X-Content-Type-Options "nosniff" always; + add_header X-Frame-Options "SAMEORIGIN" always; + add_header Referrer-Policy "strict-origin-when-cross-origin" always; + add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always; + + gzip on; + gzip_vary on; + gzip_min_length 512; + gzip_types text/css application/javascript image/svg+xml; + + location = /healthz { + access_log off; + default_type text/plain; + return 200 "ok\n"; + } + + location = / { + expires -1; + try_files /index.html =404; + } + + location ~* \.html$ { + expires -1; + try_files $uri =404; + } + + location ~* \.(?:css|js)$ { + expires 1h; + try_files $uri =404; + } + + location ^~ /public/images/ { + expires 30d; + try_files $uri =404; + } + + location / { + try_files $uri $uri/ =404; + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..dbebc09 --- /dev/null +++ b/package.json @@ -0,0 +1,10 @@ +{ + "name": "hardtschule-karlsruhe", + "version": "1.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "node server.mjs", + "start": "node server.mjs" + } +} diff --git a/public/images/hardtschule-anbau.jpg b/public/images/hardtschule-anbau.jpg new file mode 100644 index 0000000..83c7e7c Binary files /dev/null and b/public/images/hardtschule-anbau.jpg differ diff --git a/public/images/hardtschule-fassade.jpg b/public/images/hardtschule-fassade.jpg new file mode 100644 index 0000000..e126b95 Binary files /dev/null and b/public/images/hardtschule-fassade.jpg differ diff --git a/public/images/hardtschule-hero.jpg b/public/images/hardtschule-hero.jpg new file mode 100644 index 0000000..c96a8b0 Binary files /dev/null and b/public/images/hardtschule-hero.jpg differ diff --git a/public/images/logo.png b/public/images/logo.png new file mode 100644 index 0000000..ebbbb79 Binary files /dev/null and b/public/images/logo.png differ diff --git a/script.js b/script.js new file mode 100644 index 0000000..d1772c2 --- /dev/null +++ b/script.js @@ -0,0 +1,267 @@ +const menuButton = document.querySelector("[data-menu-button]"); +const mobileNav = document.querySelector("[data-mobile-nav]"); +const dialog = document.querySelector("[data-dialog]"); +const dialogTitle = document.querySelector("[data-dialog-title]"); +const dialogKicker = document.querySelector("[data-dialog-kicker]"); +const dialogContent = document.querySelector("[data-dialog-content]"); +const dialogActions = document.querySelector("[data-dialog-actions]"); +const dialogClose = document.querySelector("[data-dialog-close]"); + +const detailContent = { + schulanfang: { + kicker: "Für zukünftige Erstklässler*innen", + title: "Ein guter Start in die Schule", + html: ` +

Die Hardtschule informiert Familien rechtzeitig über Schulanmeldung, Kennenlernnachmittag, Elternabend und Einschulung.

+

Für verbindliche Termine des kommenden Schuljahres wenden Sie sich bitte an das Sekretariat. So landen keine veralteten Termine aus dem Webarchiv auf Ihrer Merkliste.

+
Dieser Prototyp ist bereits für eine jährlich aktualisierbare Termin- und Downloadpflege vorbereitet.
+ `, + actions: [ + { label: "Sekretariat anrufen", href: "tel:+497211334686", primary: true }, + { label: "E-Mail schreiben", href: "mailto:schulleitung@hardtschule-karlsruhe.de" }, + ], + }, + materiallisten: { + kicker: "Downloads", + title: "Materiallisten klar nach Klasse sortiert", + html: ` +

Vorgesehen sind aktuelle Listen für Klasse 1, 2, 3, 4 sowie die VKL. Frühere Listen aus dem Schuljahr 2025/26 wurden bewusst nicht als aktuell übernommen.

+

Bis die neuen PDF-Dateien von der Schule eingestellt sind, erhalten Familien die verbindliche Liste über die Klassenleitung oder das Sekretariat.

+
Gut erhaltene Schulsachen können in der Regel weiterverwendet werden – bitte immer die aktuelle Klassenliste beachten.
+ `, + actions: [ + { label: "Liste anfragen", href: "mailto:schulleitung@hardtschule-karlsruhe.de?subject=Aktuelle%20Materialliste", primary: true }, + { label: "Sekretariat anrufen", href: "tel:+497211334686" }, + ], + }, + bewegung: { + kicker: "Schulprofil", + title: "Bewegung gehört zum Lernen", + html: ` +

Die Hardtschule ist seit 2010 als Grundschule mit sport- und bewegungserzieherischem Schwerpunkt zertifiziert und wurde 2016 erfolgreich rezertifiziert.

+ +

So können Kinder nach konzentrierten Arbeitsphasen neue Energie sammeln und Lernen mit allen Sinnen erleben.

+ `, + actions: [{ label: "Zur Schulgemeinschaft", href: "#gemeinschaft", primary: true }], + }, + miteinander: { + kicker: "Soziales Lernen", + title: "Respekt wird jeden Tag geübt", + html: ` +

Das 2023 verabschiedete Sozialcurriculum bildet die Grundlage für Prävention und soziales Lernen.

+ +

Ergänzend finden bedarfsgerechte Projekte mit externen Partnern statt – etwa Theaterpädagogik, Selbstbehauptung und Klassentraining.

+ `, + actions: [{ label: "Beratung kennenlernen", action: "beratung", primary: true }], + }, + sprache: { + kicker: "VKL & Deutschförderung", + title: "Sprache schafft Zugehörigkeit", + html: ` +

In der Vorbereitungsklasse (VKL) lernen neu zugewanderte Kinder Deutsch und finden schrittweise in den Schulalltag hinein.

+

Die Förderung verbindet sprachliches Lernen mit Begegnung, Orientierung und der Teilnahme an der Schulgemeinschaft. Nach dem Wechsel in eine Regelklasse kann nachgehende Deutschförderung unterstützen.

+
Aufnahme und Förderumfang werden individuell mit Schule und zuständigen Stellen abgestimmt.
+ `, + actions: [ + { label: "VKL-Anfrage senden", href: "mailto:schulleitung@hardtschule-karlsruhe.de?subject=Anfrage%20zur%20VKL", primary: true }, + { label: "Sekretariat anrufen", href: "tel:+497211334686" }, + ], + }, + rundgang: { + kicker: "Gebäude & Gelände", + title: "Willkommen in der Hardtschule", + html: ` +

Im historischen Schulhaus befinden sich Klassenräume, Sekretariat und Rektorat. Das Lesezimmer wird auch für den Unterricht der VKL genutzt.

+ +

Der denkmalgeschützte Anbau von 1906 wurde 2020 behutsam saniert. Historische Materialien blieben dabei erhalten.

+ `, + actions: [ + { label: "Anfahrt ansehen", href: "#kontakt", primary: true }, + { label: "Städtisches Bauprojekt", href: "https://www.karlsruhe.de/mobilitaet-stadtbild/hochbau-und-architektur/neubauten-und-bauen-im-bestand/hardtschule-brandschutz-und-wc-sanierung", external: true }, + ], + }, + mitbestimmung: { + kicker: "Schüler*innenparlament", + title: "Kinder gestalten ihre Schule mit", + html: ` +

Klassensprecher*innen bringen die Perspektiven ihrer Klassen in das Schüler*innenparlament ein. Sie hören zu, vertreten Interessen und helfen dabei, gemeinsame Lösungen zu finden.

+

Klassenrat, Pausenengel und soziale Lernstunden geben Beteiligung einen festen Platz im Alltag – nicht nur bei besonderen Projekten.

+ `, + actions: [{ label: "Mehr zum sozialen Lernen", action: "miteinander", primary: true }], + }, + beratung: { + kicker: "Schulsozialarbeit", + title: "Vertrauliche Hilfe direkt an der Schule", + html: ` +

Die Schulsozialarbeit ist ein Beratungsangebot der Stadt Karlsruhe für Schüler*innen, Erziehungsberechtigte und das Kollegium.

+ +

Telefon Schulsozialarbeit: 0721 133-5755
Sprechzeiten: Montag, Mittwoch, Donnerstag und Freitag, 9:00–13:00 Uhr. Individuelle Termine sind möglich.

+ `, + actions: [ + { label: "Schulsozialarbeit anrufen", href: "tel:+497211335755", primary: true }, + { label: "Infos der Stadt", href: "https://www.karlsruhe.de/schuso", external: true }, + ], + }, + foerderverein: { + kicker: "Engagement", + title: "Gemeinsam mehr möglich machen", + html: ` +

Der Förderverein unterstützt Lern- und Erfahrungsmöglichkeiten, die allen Kindern der Hardtschule zugutekommen.

+ +

Mitgliedschaft und Mithilfe stärken ein solidarisches Miteinander im Interesse aller Kinder.

+ `, + actions: [{ label: "Mitgliedschaft anfragen", href: "mailto:schulleitung@hardtschule-karlsruhe.de?subject=Kontakt%20zum%20F%C3%B6rderverein", primary: true }], + }, +}; + +function setMenu(open) { + if (!menuButton || !mobileNav) return; + menuButton.setAttribute("aria-expanded", String(open)); + mobileNav.hidden = !open; + document.body.classList.toggle("menu-open", open); +} + +menuButton?.addEventListener("click", () => { + setMenu(menuButton.getAttribute("aria-expanded") !== "true"); +}); + +mobileNav?.querySelectorAll("a").forEach((link) => { + link.addEventListener("click", () => setMenu(false)); +}); + +function renderActions(actions = []) { + dialogActions.innerHTML = ""; + actions.forEach((action) => { + const element = document.createElement("a"); + element.className = `button ${action.primary ? "button-dark" : "button-outline"}`; + element.textContent = action.label; + + if (action.action) { + element.href = "#"; + element.addEventListener("click", (event) => { + event.preventDefault(); + openDetail(action.action); + }); + } else { + element.href = action.href; + if (action.external) { + element.target = "_blank"; + element.rel = "noreferrer"; + } + if (action.href?.startsWith("#")) { + element.addEventListener("click", () => dialog.close()); + } + } + + const arrow = document.createElementNS("http://www.w3.org/2000/svg", "svg"); + arrow.setAttribute("aria-hidden", "true"); + const use = document.createElementNS("http://www.w3.org/2000/svg", "use"); + use.setAttribute("href", "#icon-arrow"); + arrow.append(use); + element.append(arrow); + dialogActions.append(element); + }); +} + +function openDetail(key) { + const content = detailContent[key]; + if (!content || !dialog) return; + + dialogKicker.textContent = content.kicker; + dialogTitle.textContent = content.title; + dialogContent.innerHTML = content.html; + renderActions(content.actions); + + if (!dialog.open) dialog.showModal(); + document.body.classList.add("dialog-open"); +} + +document.querySelectorAll("[data-detail]").forEach((trigger) => { + trigger.addEventListener("click", () => openDetail(trigger.dataset.detail)); +}); + +dialogClose?.addEventListener("click", () => dialog.close()); + +dialog?.addEventListener("click", (event) => { + if (event.target === dialog) dialog.close(); +}); + +dialog?.addEventListener("close", () => { + document.body.classList.remove("dialog-open"); +}); + +document.querySelectorAll("[data-year]").forEach((element) => { + element.textContent = new Date().getFullYear(); +}); + +const revealElements = document.querySelectorAll(".reveal"); +const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches; + +if (reduceMotion || !("IntersectionObserver" in window)) { + revealElements.forEach((element) => element.classList.add("is-visible")); +} else { + const revealObserver = new IntersectionObserver( + (entries, observer) => { + entries.forEach((entry) => { + if (!entry.isIntersecting) return; + entry.target.classList.add("is-visible"); + observer.unobserve(entry.target); + }); + }, + { threshold: 0.12, rootMargin: "0px 0px -40px" }, + ); + + revealElements.forEach((element) => revealObserver.observe(element)); +} + +const navLinks = [...document.querySelectorAll(".desktop-nav a")]; +const sections = navLinks + .map((link) => document.querySelector(link.getAttribute("href"))) + .filter(Boolean); + +if ("IntersectionObserver" in window && navLinks.length) { + const sectionObserver = new IntersectionObserver( + (entries) => { + const visible = entries + .filter((entry) => entry.isIntersecting) + .sort((a, b) => b.intersectionRatio - a.intersectionRatio)[0]; + if (!visible) return; + + navLinks.forEach((link) => { + const active = link.getAttribute("href") === `#${visible.target.id}`; + if (active) link.setAttribute("aria-current", "true"); + else link.removeAttribute("aria-current"); + }); + }, + { rootMargin: "-30% 0px -60%", threshold: [0, 0.1, 0.3] }, + ); + + sections.forEach((section) => sectionObserver.observe(section)); +} diff --git a/server.mjs b/server.mjs new file mode 100644 index 0000000..ec6533f --- /dev/null +++ b/server.mjs @@ -0,0 +1,38 @@ +import { createReadStream, existsSync, statSync } from "node:fs"; +import { createServer } from "node:http"; +import { extname, join, normalize } from "node:path"; + +const root = process.cwd(); +const port = Number(process.env.PORT || 4173); + +const mimeTypes = { + ".css": "text/css; charset=utf-8", + ".html": "text/html; charset=utf-8", + ".js": "text/javascript; charset=utf-8", + ".jpg": "image/jpeg", + ".jpeg": "image/jpeg", + ".png": "image/png", + ".svg": "image/svg+xml", +}; + +createServer((request, response) => { + const pathname = decodeURIComponent(new URL(request.url, `http://${request.headers.host}`).pathname); + const requested = pathname === "/" ? "/index.html" : pathname; + const safePath = normalize(requested).replace(/^(\.\.(\/|\\|$))+/, ""); + let filePath = join(root, safePath); + + if (!filePath.startsWith(root) || !existsSync(filePath)) { + response.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" }); + response.end("Nicht gefunden"); + return; + } + + if (statSync(filePath).isDirectory()) filePath = join(filePath, "index.html"); + response.writeHead(200, { + "Content-Type": mimeTypes[extname(filePath).toLowerCase()] || "application/octet-stream", + "Cache-Control": "no-cache", + }); + createReadStream(filePath).pipe(response); +}).listen(port, "127.0.0.1", () => { + console.log(`Hardtschule-Website: http://127.0.0.1:${port}`); +}); diff --git a/styles.css b/styles.css new file mode 100644 index 0000000..3d32abd --- /dev/null +++ b/styles.css @@ -0,0 +1,2487 @@ +:root { + --ink: #17302b; + --ink-soft: #4b5e59; + --green-950: #073a31; + --green-900: #0c4a3e; + --green-800: #145e4f; + --green-100: #dcebe4; + --blue-700: #255da8; + --blue-100: #dce9f8; + --coral-600: #e76850; + --coral-100: #f8ded7; + --sun-500: #f5c95d; + --sun-100: #fff0bd; + --cream-50: #fbf9f2; + --cream-100: #f4efe2; + --white: #ffffff; + --shadow-soft: 0 1px 2px rgba(23, 48, 43, 0.05), 0 12px 32px rgba(23, 48, 43, 0.08); + --shadow-float: 0 1px 0 rgba(255, 255, 255, 0.24) inset, 0 18px 50px rgba(0, 27, 22, 0.2); + --radius-sm: 12px; + --radius-md: 18px; + --radius-lg: 28px; + --radius-xl: 40px; + --shell: min(1180px, calc(100vw - 40px)); + --font-display: Georgia, "Times New Roman", serif; + --font-sans: "Avenir Next", Avenir, "Segoe UI", Helvetica, Arial, sans-serif; +} + +*, +*::before, +*::after { + box-sizing: border-box; +} + +html { + scroll-behavior: smooth; + scroll-padding-top: 108px; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +body { + margin: 0; + background: var(--cream-50); + color: var(--ink); + font-family: var(--font-sans); + font-size: 16px; + line-height: 1.6; +} + +body.menu-open, +body.dialog-open { + overflow: hidden; +} + +img { + display: block; + max-width: 100%; + outline: 1px solid rgba(7, 58, 49, 0.08); + outline-offset: -1px; +} + +button, +a { + font: inherit; +} + +a { + color: inherit; + text-decoration: none; +} + +button { + color: inherit; +} + +p { + margin: 0; + text-wrap: pretty; +} + +h1, +h2, +h3 { + margin: 0; + line-height: 1.05; + text-wrap: balance; +} + +h1, +h2 { + font-family: var(--font-display); + font-weight: 400; + letter-spacing: -0.045em; +} + +h1 em, +h2 em { + color: var(--sun-500); + font-weight: 400; +} + +h3 { + font-size: 1.35rem; + letter-spacing: -0.025em; +} + +svg { + display: block; + fill: none; + stroke: currentColor; + stroke-linecap: round; + stroke-linejoin: round; + stroke-width: 1.8; +} + +.shell { + width: var(--shell); + margin-inline: auto; +} + +.section { + padding: 112px 0; +} + +.svg-library, +.sr-only { + position: absolute; + width: 1px; + height: 1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; +} + +.skip-link { + position: fixed; + z-index: 1000; + top: 12px; + left: 12px; + padding: 10px 16px; + border-radius: 8px; + background: var(--white); + color: var(--green-950); + font-weight: 700; + transform: translateY(-150%); + transition: transform 180ms ease-out; +} + +.skip-link:focus { + transform: translateY(0); +} + +.utility-bar { + background: var(--green-950); + color: rgba(255, 255, 255, 0.82); + font-size: 0.78rem; + font-weight: 600; + letter-spacing: 0.02em; +} + +.utility-inner { + min-height: 34px; + display: flex; + align-items: center; + justify-content: space-between; +} + +.utility-inner a { + display: inline-flex; + align-items: center; + gap: 7px; + min-height: 34px; +} + +.utility-inner svg { + width: 14px; + height: 14px; +} + +.site-header { + position: sticky; + z-index: 100; + top: 0; + background: rgba(251, 249, 242, 0.94); + border-bottom: 1px solid rgba(23, 48, 43, 0.08); + backdrop-filter: blur(16px); +} + +.header-inner { + min-height: 80px; + display: flex; + align-items: center; + gap: 30px; +} + +.brand { + display: inline-flex; + align-items: center; + gap: 12px; + flex-shrink: 0; +} + +.brand-mark { + position: relative; + width: 48px; + height: 48px; + display: grid; + place-items: center; + border-radius: 15px; + background: var(--green-900); + box-shadow: 0 1px 0 rgba(255, 255, 255, 0.18) inset, 0 6px 16px rgba(7, 58, 49, 0.16); +} + +.brand-roof { + position: absolute; + width: 24px; + height: 24px; + top: 10px; + transform: rotate(45deg); + border-top: 4px solid var(--sun-500); + border-left: 4px solid var(--sun-500); + border-radius: 2px; +} + +.brand-door { + position: absolute; + width: 22px; + height: 16px; + bottom: 9px; + border: 4px solid var(--white); + border-bottom: 0; + border-radius: 4px 4px 0 0; +} + +.brand-copy { + display: flex; + flex-direction: column; + line-height: 1; +} + +.brand-copy strong { + font-family: var(--font-display); + font-size: 1.35rem; + letter-spacing: -0.04em; +} + +.brand-copy span { + margin-top: 4px; + color: var(--green-800); + font-size: 0.68rem; + font-weight: 800; + letter-spacing: 0.15em; + text-transform: uppercase; +} + +.desktop-nav { + display: flex; + align-items: center; + gap: 7px; + margin-left: auto; +} + +.desktop-nav a { + position: relative; + display: grid; + min-height: 44px; + place-items: center; + padding: 0 12px; + color: var(--ink-soft); + font-size: 0.9rem; + font-weight: 650; +} + +.desktop-nav a::after { + content: ""; + position: absolute; + right: 12px; + bottom: 6px; + left: 12px; + height: 2px; + border-radius: 2px; + background: var(--coral-600); + transform: scaleX(0); + transform-origin: left; + transition-property: transform; + transition-duration: 180ms; + transition-timing-function: ease-out; +} + +.desktop-nav a:hover::after, +.desktop-nav a[aria-current="true"]::after { + transform: scaleX(1); +} + +.button { + display: inline-flex; + min-height: 52px; + align-items: center; + justify-content: center; + gap: 10px; + padding: 0 18px 0 20px; + border: 0; + border-radius: 15px; + cursor: pointer; + font-size: 0.9rem; + font-weight: 750; + box-shadow: var(--shadow-soft); + transition-property: background-color, color, box-shadow, scale, transform; + transition-duration: 160ms; + transition-timing-function: ease-out; +} + +.button svg, +.text-link svg { + width: 18px; + height: 18px; + transition-property: transform; + transition-duration: 180ms; + transition-timing-function: ease-out; +} + +.button:hover svg, +.text-link:hover svg { + transform: translateX(3px); +} + +.button:active, +.quick-card:active, +.dialog-close:active, +.menu-button:active { + scale: 0.96; +} + +.button-small { + min-height: 44px; + padding-right: 15px; + padding-left: 17px; + border-radius: 13px; + font-size: 0.82rem; +} + +.button-dark { + background: var(--green-900); + color: var(--white); +} + +.button-dark:hover { + background: var(--green-800); + box-shadow: 0 1px 2px rgba(7, 58, 49, 0.08), 0 10px 24px rgba(7, 58, 49, 0.16); +} + +.button-sun { + background: var(--sun-500); + color: var(--green-950); +} + +.button-sun:hover { + background: #ffd879; +} + +.button-outline { + background: transparent; + color: var(--green-900); + box-shadow: 0 0 0 1px rgba(12, 74, 62, 0.22), 0 2px 5px rgba(7, 58, 49, 0.05); +} + +.button-outline:hover { + background: var(--green-100); + box-shadow: 0 0 0 1px rgba(12, 74, 62, 0.3), 0 5px 12px rgba(7, 58, 49, 0.08); +} + +.text-link { + display: inline-flex; + align-items: center; + gap: 8px; + width: fit-content; + min-height: 44px; + padding: 0; + border: 0; + background: transparent; + color: var(--green-900); + cursor: pointer; + font-size: 0.86rem; + font-weight: 750; +} + +.text-link-light { + color: var(--white); +} + +.menu-button { + display: none; + width: 44px; + height: 44px; + border: 0; + border-radius: 12px; + background: var(--green-100); + cursor: pointer; + place-content: center; + gap: 4px; +} + +.menu-button span:not(.sr-only) { + display: block; + width: 20px; + height: 2px; + border-radius: 2px; + background: var(--green-900); + transition-property: transform, opacity; + transition-duration: 180ms; + transition-timing-function: ease-out; +} + +.menu-button[aria-expanded="true"] span:nth-of-type(2) { + transform: translateY(6px) rotate(45deg); +} + +.menu-button[aria-expanded="true"] span:nth-of-type(3) { + opacity: 0; +} + +.menu-button[aria-expanded="true"] span:nth-of-type(4) { + transform: translateY(-6px) rotate(-45deg); +} + +.mobile-nav { + border-top: 1px solid rgba(23, 48, 43, 0.08); + background: var(--cream-50); +} + +.mobile-nav-inner { + display: grid; + padding-top: 14px; + padding-bottom: 18px; +} + +.mobile-nav a { + display: flex; + min-height: 48px; + align-items: center; + border-bottom: 1px solid rgba(23, 48, 43, 0.08); + font-family: var(--font-display); + font-size: 1.2rem; +} + +.hero { + position: relative; + min-height: 680px; + overflow: hidden; + background: var(--green-900); + color: var(--white); +} + +.hero::before { + content: ""; + position: absolute; + width: 470px; + height: 470px; + left: -260px; + bottom: -230px; + border: 90px solid rgba(245, 201, 93, 0.12); + border-radius: 50%; +} + +.hero-dots { + position: absolute; + top: 60px; + right: -20px; + width: 190px; + height: 190px; + opacity: 0.2; + background-image: radial-gradient(var(--sun-500) 1.7px, transparent 1.7px); + background-size: 18px 18px; + transform: rotate(9deg); +} + +.hero-grid { + position: relative; + z-index: 2; + display: grid; + min-height: 650px; + grid-template-columns: 0.94fr 1.06fr; + align-items: center; + gap: clamp(50px, 7vw, 96px); + padding-top: 70px; + padding-bottom: 90px; +} + +.eyebrow { + display: flex; + align-items: center; + gap: 10px; + color: var(--green-800); + font-size: 0.73rem; + font-weight: 850; + letter-spacing: 0.16em; + text-transform: uppercase; +} + +.eyebrow::before { + content: ""; + width: 28px; + height: 2px; + border-radius: 2px; + background: var(--coral-600); +} + +.eyebrow-light { + color: rgba(255, 255, 255, 0.78); +} + +.eyebrow-light::before { + background: var(--sun-500); +} + +.hero h1 { + max-width: 650px; + margin-top: 22px; + font-size: clamp(3.25rem, 6vw, 5.7rem); +} + +.hero-lead { + max-width: 580px; + margin-top: 28px; + color: rgba(255, 255, 255, 0.78); + font-size: clamp(1rem, 1.5vw, 1.16rem); + line-height: 1.7; +} + +.hero-actions { + display: flex; + align-items: center; + gap: 24px; + margin-top: 34px; +} + +.hero-signals { + display: flex; + flex-wrap: wrap; + gap: 12px 22px; + margin-top: 44px; + color: rgba(255, 255, 255, 0.66); + font-size: 0.75rem; + font-weight: 650; +} + +.hero-signals span { + display: inline-flex; + align-items: center; + gap: 8px; +} + +.signal-dot { + width: 7px; + height: 7px; + border-radius: 50%; +} + +.signal-yellow { background: var(--sun-500); } +.signal-coral { background: #ff8a71; } +.signal-blue { background: #92c5ff; } + +.hero-visual { + position: relative; + min-width: 0; + padding: 30px 20px 20px 10px; +} + +.hero-image-wrap { + position: relative; + overflow: hidden; + aspect-ratio: 0.95; + border-radius: 160px 32px 32px 32px; + box-shadow: var(--shadow-float); +} + +.hero-image-wrap::after { + content: ""; + position: absolute; + inset: 0; + background: linear-gradient(180deg, transparent 65%, rgba(7, 58, 49, 0.34)); + pointer-events: none; +} + +.hero-image-wrap img { + width: 100%; + height: 100%; + object-fit: cover; + object-position: 50% 50%; +} + +.photo-credit { + position: absolute; + z-index: 2; + right: 16px; + bottom: 13px; + color: rgba(255, 255, 255, 0.82); + font-size: 0.58rem; +} + +.hero-sticker { + position: absolute; + z-index: 3; + display: flex; + box-shadow: 0 14px 34px rgba(7, 36, 31, 0.25); +} + +.sticker-year { + top: 8px; + right: -12px; + width: 126px; + height: 126px; + flex-direction: column; + align-items: center; + justify-content: center; + border-radius: 50%; + background: var(--sun-500); + color: var(--green-950); + line-height: 1.05; + transform: rotate(8deg); +} + +.sticker-year strong { + font-family: var(--font-display); + font-size: 2rem; +} + +.sticker-year span { + font-size: 0.58rem; + font-weight: 750; + letter-spacing: 0.05em; + text-transform: uppercase; +} + +.sticker-move { + left: -40px; + bottom: 58px; + align-items: center; + gap: 10px; + padding: 13px 16px; + border-radius: 16px; + background: var(--coral-600); + color: var(--white); + font-size: 0.76rem; + font-weight: 800; + line-height: 1.2; + transform: rotate(-4deg); +} + +.sticker-move svg { + width: 27px; + height: 27px; +} + +.hero-wave { + position: absolute; + z-index: 3; + right: -2%; + bottom: -34px; + left: -2%; + height: 70px; + border-radius: 50% 50% 0 0; + background: var(--cream-50); +} + +.quick-section { + padding: 68px 0 42px; +} + +.quick-heading { + display: flex; + align-items: end; + justify-content: space-between; + gap: 40px; +} + +.quick-heading h2 { + margin-top: 12px; + font-size: clamp(2rem, 4vw, 3.35rem); +} + +.quick-heading > p { + max-width: 380px; + color: var(--ink-soft); +} + +.quick-grid { + display: grid; + grid-template-columns: repeat(5, 1fr); + gap: 12px; + margin-top: 30px; +} + +.quick-card { + position: relative; + display: flex; + min-width: 0; + min-height: 156px; + flex-direction: column; + align-items: flex-start; + justify-content: space-between; + padding: 20px; + border: 0; + border-radius: 22px; + background: var(--white); + color: var(--ink); + cursor: pointer; + text-align: left; + box-shadow: 0 0 0 1px rgba(23, 48, 43, 0.06), 0 6px 18px rgba(23, 48, 43, 0.06); + transition-property: transform, box-shadow; + transition-duration: 180ms; + transition-timing-function: ease-out; +} + +.quick-card:hover { + transform: translateY(-4px); + box-shadow: 0 0 0 1px rgba(23, 48, 43, 0.08), 0 14px 32px rgba(23, 48, 43, 0.1); +} + +.quick-icon { + display: grid; + width: 43px; + height: 43px; + place-items: center; + border-radius: 13px; + background: rgba(255, 255, 255, 0.7); +} + +.quick-icon svg { + width: 23px; + height: 23px; +} + +.quick-card > span:nth-child(2) { + display: flex; + flex-direction: column; + padding-right: 18px; +} + +.quick-card strong { + font-size: 0.9rem; +} + +.quick-card small { + margin-top: 3px; + color: rgba(23, 48, 43, 0.68); + font-size: 0.67rem; + line-height: 1.35; +} + +.quick-arrow { + position: absolute; + right: 17px; + bottom: 20px; + width: 18px; + height: 18px; + transition-property: transform; + transition-duration: 180ms; + transition-timing-function: ease-out; +} + +.quick-card:hover .quick-arrow { + transform: translateX(3px); +} + +.quick-blue { background: var(--blue-100); } +.quick-coral { background: var(--coral-100); } +.quick-yellow { background: var(--sun-100); } +.quick-green { background: var(--green-100); } +.quick-cream { background: var(--cream-100); } + +.section-heading h2 { + font-size: clamp(2.55rem, 5vw, 4.35rem); +} + +.section-heading h2 em { + color: var(--coral-600); +} + +.section-heading-centered { + max-width: 760px; + margin-inline: auto; + text-align: center; +} + +.section-heading-centered .eyebrow { + justify-content: center; +} + +.section-heading-centered h2 { + margin-top: 18px; +} + +.section-heading-centered > p:last-child { + max-width: 620px; + margin: 22px auto 0; + color: var(--ink-soft); + font-size: 1.05rem; +} + +.profile-section { + padding-top: 86px; +} + +.profile-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 18px; + margin-top: 54px; +} + +.profile-card { + position: relative; + display: flex; + min-height: 480px; + flex-direction: column; + overflow: hidden; + padding: 32px; + border-radius: var(--radius-lg); + box-shadow: 0 0 0 1px rgba(23, 48, 43, 0.06), 0 12px 32px rgba(23, 48, 43, 0.06); +} + +.profile-card::before { + content: ""; + position: absolute; + width: 180px; + height: 180px; + top: -90px; + right: -60px; + border: 28px solid rgba(255, 255, 255, 0.35); + border-radius: 50%; +} + +.profile-movement { background: var(--sun-100); } +.profile-community { background: var(--coral-100); } +.profile-language { background: var(--blue-100); } + +.profile-icon { + display: grid; + width: 58px; + height: 58px; + place-items: center; + border-radius: 17px; + background: rgba(255, 255, 255, 0.72); + box-shadow: 0 1px 4px rgba(23, 48, 43, 0.07); +} + +.profile-icon svg { + width: 31px; + height: 31px; +} + +.profile-number { + position: absolute; + top: 26px; + right: 30px; + color: rgba(23, 48, 43, 0.3); + font-size: 0.75rem; + font-weight: 800; +} + +.profile-card h3 { + margin-top: 40px; + font-family: var(--font-display); + font-size: 2rem; + font-weight: 400; +} + +.profile-card > p { + margin-top: 16px; + color: var(--ink-soft); +} + +.profile-fact { + display: grid; + grid-template-columns: 72px 1fr; + gap: 14px; + margin-top: auto; + padding: 20px 0; + border-top: 1px solid rgba(23, 48, 43, 0.12); + border-bottom: 1px solid rgba(23, 48, 43, 0.12); +} + +.profile-fact strong { + font-size: 0.82rem; + line-height: 1.3; +} + +.profile-fact span { + color: var(--ink-soft); + font-size: 0.7rem; + line-height: 1.5; +} + +.profile-card .text-link { + margin-top: 12px; +} + +.place-section { + overflow: hidden; + background: var(--cream-100); +} + +.place-grid { + display: grid; + grid-template-columns: 1.08fr 0.92fr; + align-items: center; + gap: clamp(60px, 8vw, 110px); +} + +.place-visual { + position: relative; + min-height: 610px; +} + +.place-visual::before { + content: ""; + position: absolute; + width: 280px; + height: 280px; + top: -35px; + left: -70px; + border-radius: 50%; + background: var(--sun-500); + opacity: 0.38; +} + +.place-image-main { + position: absolute; + z-index: 1; + width: 79%; + height: 530px; + top: 0; + left: 0; + object-fit: cover; + border-radius: 150px 24px 24px 24px; + box-shadow: var(--shadow-soft); +} + +.place-image-small { + position: absolute; + z-index: 2; + right: 0; + bottom: 0; + width: 44%; + aspect-ratio: 1; + object-fit: cover; + border: 10px solid var(--cream-100); + border-radius: 28px; + box-shadow: var(--shadow-soft); +} + +.place-caption { + position: absolute; + z-index: 3; + bottom: 50px; + left: 28px; + padding: 13px 16px; + border-radius: 12px; + background: var(--green-900); + color: var(--white); + font-family: var(--font-display); + font-size: 0.93rem; + line-height: 1.3; + transform: rotate(-3deg); +} + +.place-copy h2 { + margin-top: 18px; + font-size: clamp(2.7rem, 5vw, 4.4rem); +} + +.place-copy h2 em { + color: var(--coral-600); +} + +.place-lead { + margin-top: 24px; + color: var(--ink-soft); + font-size: 1.08rem; + line-height: 1.72; +} + +.place-facts { + display: grid; + gap: 0; + margin: 32px 0 24px; + border-top: 1px solid rgba(23, 48, 43, 0.14); +} + +.place-facts div { + display: grid; + grid-template-columns: 124px 1fr; + gap: 20px; + padding: 14px 0; + border-bottom: 1px solid rgba(23, 48, 43, 0.14); + align-items: center; +} + +.place-facts strong { + color: var(--green-900); + font-family: var(--font-display); + font-size: 1.17rem; + font-weight: 400; +} + +.place-facts span { + color: var(--ink-soft); + font-size: 0.78rem; +} + +.place-copy > p:not(.eyebrow):not(.place-lead) { + color: var(--ink-soft); + font-size: 0.92rem; +} + +.place-copy .button { + margin-top: 26px; +} + +.image-source { + display: block; + margin-top: 16px; + color: rgba(23, 48, 43, 0.48); + font-size: 0.62rem; +} + +.life-section { + position: relative; + overflow: hidden; + background: var(--green-900); + color: var(--white); +} + +.life-section::before { + content: ""; + position: absolute; + width: 300px; + height: 300px; + right: -170px; + bottom: -170px; + border: 56px solid rgba(245, 201, 93, 0.12); + border-radius: 50%; +} + +.section-heading-split { + display: grid; + grid-template-columns: 1.1fr 0.9fr; + align-items: end; + gap: 80px; +} + +.section-heading-split h2 { + max-width: 690px; + margin-top: 18px; +} + +.section-heading-split > p { + max-width: 430px; + padding-bottom: 8px; + color: rgba(255, 255, 255, 0.68); +} + +.story-grid { + display: grid; + grid-template-columns: 1.15fr 0.85fr 0.85fr; + grid-template-rows: 365px 280px; + gap: 16px; + margin-top: 54px; +} + +.story-card { + position: relative; + display: flex; + overflow: hidden; + flex-direction: column; + justify-content: flex-end; + padding: 28px; + border-radius: var(--radius-lg); + color: var(--ink); + box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.08), 0 16px 38px rgba(0, 25, 21, 0.18); +} + +.story-large { + grid-row: span 2; +} + +.story-wide { + grid-column: span 2; + flex-direction: row; + align-items: end; + justify-content: space-between; + color: var(--white); +} + +.story-yellow { background: var(--sun-500); } +.story-blue { background: #8fb9e9; } +.story-coral { background: #ef8d77; } +.story-green { background: var(--green-800); } + +.story-copy { + position: relative; + z-index: 2; + max-width: 470px; +} + +.story-tag { + display: inline-flex; + padding: 5px 10px; + border-radius: 999px; + background: rgba(255, 255, 255, 0.66); + font-size: 0.61rem; + font-weight: 800; + letter-spacing: 0.06em; + text-transform: uppercase; +} + +.story-green .story-tag { + background: rgba(255, 255, 255, 0.14); +} + +.story-card h3 { + margin-top: 12px; + font-family: var(--font-display); + font-size: clamp(1.45rem, 2.5vw, 2.3rem); + font-weight: 400; +} + +.story-card p { + margin-top: 9px; + color: rgba(23, 48, 43, 0.72); + font-size: 0.8rem; +} + +.story-green p { + color: rgba(255, 255, 255, 0.7); +} + +.story-green .text-link { + margin-top: 10px; +} + +.story-art { + position: absolute; + pointer-events: none; +} + +.story-art-letters { + top: 45px; + right: 30px; + left: 30px; + height: 310px; +} + +.story-art-letters span { + position: absolute; + display: grid; + width: 96px; + height: 112px; + place-items: center; + border: 4px solid var(--green-900); + border-radius: 18px; + background: rgba(255, 255, 255, 0.36); + font-family: var(--font-display); + font-size: 4.2rem; +} + +.story-art-letters span:nth-child(1) { left: 5%; top: 10px; transform: rotate(-8deg); } +.story-art-letters span:nth-child(2) { left: 36%; top: 70px; transform: rotate(4deg); } +.story-art-letters span:nth-child(3) { right: 3%; top: 20px; transform: rotate(9deg); } + +.story-art-letters i { + position: absolute; + width: 12px; + height: 12px; + border-radius: 50%; + background: var(--coral-600); +} + +.story-art-letters i:nth-of-type(1) { left: 15%; top: 168px; } +.story-art-letters i:nth-of-type(2) { right: 8%; top: 174px; width: 18px; height: 18px; } +.story-art-letters i:nth-of-type(3) { left: 60%; top: 8px; width: 8px; height: 8px; } + +.story-art-robot { + top: 28px; + right: 30px; + width: 135px; + height: 170px; +} + +.robot-head { + position: absolute; + top: 20px; + left: 24px; + width: 90px; + height: 70px; + border: 4px solid var(--green-950); + border-radius: 24px; + background: rgba(255, 255, 255, 0.4); +} + +.robot-head::before { + content: ""; + position: absolute; + width: 4px; + height: 26px; + top: -25px; + left: 41px; + background: var(--green-950); +} + +.robot-head::after { + content: ""; + position: absolute; + width: 12px; + height: 12px; + top: -34px; + left: 37px; + border-radius: 50%; + background: var(--coral-600); +} + +.robot-head i { + position: absolute; + width: 13px; + height: 13px; + top: 24px; + border-radius: 50%; + background: var(--green-950); +} + +.robot-head i:first-child { left: 20px; } +.robot-head i:last-child { right: 20px; } + +.robot-body { + position: absolute; + left: 39px; + bottom: 12px; + width: 61px; + height: 69px; + border: 4px solid var(--green-950); + border-radius: 12px 12px 24px 24px; + background: var(--sun-500); +} + +.robot-signal { + position: absolute; + top: 0; + right: 4px; + width: 22px; + height: 22px; + border-top: 3px solid var(--green-950); + border-right: 3px solid var(--green-950); + border-radius: 0 100% 0 0; + transform: rotate(-45deg); +} + +.story-art-print { + top: 34px; + right: 30px; + width: 145px; + height: 150px; +} + +.print-sheet { + position: absolute; + top: 8px; + left: 20px; + width: 96px; + height: 112px; + border: 4px solid var(--green-950); + background: rgba(255, 255, 255, 0.55); + transform: rotate(8deg); +} + +.print-sheet::before, +.print-sheet::after { + content: ""; + position: absolute; + left: 18px; + border-radius: 50%; + background: var(--blue-700); +} + +.print-sheet::before { width: 42px; height: 42px; top: 18px; } +.print-sheet::after { width: 24px; height: 24px; right: 12px; bottom: 10px; left: auto; background: var(--sun-500); } + +.print-roll { + position: absolute; + z-index: 2; + right: 3px; + bottom: 10px; + width: 48px; + height: 48px; + border: 4px solid var(--green-950); + border-radius: 50%; + background: var(--cream-50); +} + +.story-art-print i { + position: absolute; + z-index: 3; + right: 17px; + bottom: 25px; + width: 18px; + height: 18px; + border-radius: 50%; + background: var(--coral-600); +} + +.story-art-track { + right: 24px; + bottom: 22px; + width: 260px; + height: 220px; + opacity: 0.9; +} + +.story-art-track::before, +.story-art-track::after { + content: ""; + position: absolute; + width: 210px; + height: 110px; + right: 0; + border: 5px solid rgba(255, 255, 255, 0.32); + border-left: 0; + border-radius: 0 110px 110px 0; + transform: rotate(-15deg); +} + +.story-art-track::before { top: 25px; } +.story-art-track::after { top: 58px; right: 22px; } + +.story-art-track span, +.story-art-track i, +.story-art-track b { + position: absolute; + width: 16px; + height: 16px; + border-radius: 50%; + background: var(--sun-500); +} + +.story-art-track span { top: 12px; right: 130px; } +.story-art-track i { top: 156px; right: 40px; background: #9ac7f4; } +.story-art-track b { top: 52px; right: 12px; width: 11px; height: 11px; background: #ef8d77; } + +.community-section { + background: var(--cream-50); +} + +.community-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 18px; + margin-top: 54px; +} + +.community-card { + display: flex; + min-height: 340px; + flex-direction: column; + padding: 32px; + border-radius: var(--radius-lg); + background: var(--white); + box-shadow: 0 0 0 1px rgba(23, 48, 43, 0.06), 0 10px 30px rgba(23, 48, 43, 0.055); +} + +.community-icon { + display: grid; + width: 54px; + height: 54px; + place-items: center; + border-radius: 16px; +} + +.community-icon svg { + width: 27px; + height: 27px; +} + +.community-icon-blue { background: var(--blue-100); color: var(--blue-700); } +.community-icon-coral { background: var(--coral-100); color: var(--coral-600); } +.community-icon-yellow { background: var(--sun-100); color: #906a0c; } + +.community-card h3 { + margin-top: 28px; + font-family: var(--font-display); + font-size: 1.65rem; + font-weight: 400; +} + +.community-card p { + margin-top: 14px; + color: var(--ink-soft); + font-size: 0.88rem; +} + +.community-card .text-link { + margin-top: auto; + padding-top: 24px; +} + +.community-quote { + position: relative; + display: grid; + max-width: 860px; + margin: 74px auto 0; + place-items: center; + text-align: center; +} + +.community-quote > svg { + width: 36px; + height: 36px; + color: var(--coral-600); +} + +.community-quote p { + margin-top: 20px; + font-family: var(--font-display); + font-size: clamp(1.8rem, 4vw, 3.25rem); + letter-spacing: -0.035em; + line-height: 1.2; +} + +.community-quote cite { + margin-top: 14px; + color: var(--ink-soft); + font-size: 0.75rem; + font-style: normal; + font-weight: 700; +} + +.parents-section { + background: var(--blue-700); + color: var(--white); +} + +.parents-grid { + display: grid; + grid-template-columns: 0.76fr 1.24fr; + gap: clamp(70px, 10vw, 140px); + align-items: start; +} + +.parents-intro { + position: sticky; + top: 132px; +} + +.parents-intro h2 { + margin-top: 18px; + font-size: clamp(2.8rem, 5vw, 4.5rem); +} + +.parents-intro > p:not(.eyebrow) { + margin-top: 24px; + color: rgba(255, 255, 255, 0.74); + font-size: 1.02rem; +} + +.parents-note { + display: flex; + align-items: center; + gap: 14px; + margin-top: 40px; + padding: 18px; + border-radius: 18px; + background: rgba(255, 255, 255, 0.1); + box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.12) inset; +} + +.parents-note > svg { + width: 27px; + height: 27px; + color: var(--sun-500); +} + +.parents-note div { + display: flex; + flex-direction: column; +} + +.parents-note span { + color: rgba(255, 255, 255, 0.65); + font-size: 0.66rem; +} + +.parents-note a { + font-size: 1.05rem; + font-weight: 800; +} + +.info-accordion { + border-top: 1px solid rgba(255, 255, 255, 0.2); +} + +.info-accordion details { + border-bottom: 1px solid rgba(255, 255, 255, 0.2); +} + +.info-accordion summary { + display: grid; + min-height: 82px; + grid-template-columns: 44px 1fr 30px; + align-items: center; + gap: 10px; + cursor: pointer; + list-style: none; + font-family: var(--font-display); + font-size: 1.28rem; + transition-property: color; + transition-duration: 160ms; +} + +.info-accordion summary::-webkit-details-marker { + display: none; +} + +.info-accordion summary > span { + color: rgba(255, 255, 255, 0.44); + font-family: var(--font-sans); + font-size: 0.68rem; + font-weight: 800; +} + +.info-accordion summary > i { + position: relative; + width: 20px; + height: 20px; +} + +.info-accordion summary > i::before, +.info-accordion summary > i::after { + content: ""; + position: absolute; + top: 9px; + left: 2px; + width: 16px; + height: 2px; + border-radius: 2px; + background: currentColor; + transition-property: transform; + transition-duration: 180ms; + transition-timing-function: ease-out; +} + +.info-accordion summary > i::after { + transform: rotate(90deg); +} + +.info-accordion details[open] summary { + color: var(--sun-500); +} + +.info-accordion details[open] summary > i::after { + transform: rotate(0deg); +} + +.accordion-content { + padding: 0 46px 27px 54px; +} + +.accordion-content p { + max-width: 610px; + color: rgba(255, 255, 255, 0.72); + font-size: 0.86rem; +} + +.accordion-content .text-link { + margin-top: 10px; + color: var(--white); +} + +.contact-section { + background: var(--cream-100); +} + +.contact-grid { + display: grid; + grid-template-columns: 0.85fr 1.15fr; + align-items: center; + gap: clamp(60px, 8vw, 100px); +} + +.contact-copy h2 { + margin-top: 18px; + font-size: clamp(2.8rem, 5vw, 4.5rem); +} + +.contact-copy h2 em { + color: var(--coral-600); +} + +.contact-lead { + margin-top: 22px; + color: var(--ink-soft); +} + +.contact-list { + display: grid; + gap: 0; + margin-top: 32px; + border-top: 1px solid rgba(23, 48, 43, 0.14); +} + +.contact-list > div { + display: grid; + min-height: 94px; + grid-template-columns: 48px 1fr; + align-items: center; + gap: 14px; + border-bottom: 1px solid rgba(23, 48, 43, 0.14); +} + +.contact-icon { + display: grid; + width: 42px; + height: 42px; + place-items: center; + border-radius: 13px; + background: var(--white); + color: var(--green-900); + box-shadow: 0 1px 4px rgba(23, 48, 43, 0.07); +} + +.contact-icon svg { + width: 22px; + height: 22px; +} + +.contact-list p { + font-size: 0.82rem; + line-height: 1.55; +} + +.contact-list strong { + font-size: 0.75rem; +} + +.contact-list a { + color: var(--green-900); + font-weight: 750; + overflow-wrap: anywhere; +} + +.contact-list small { + color: var(--ink-soft); + font-size: 0.68rem; +} + +.map-card { + overflow: hidden; + padding: 10px; + border-radius: 34px; + background: var(--white); + box-shadow: 0 0 0 1px rgba(23, 48, 43, 0.06), 0 18px 45px rgba(23, 48, 43, 0.09); +} + +.map-illustration { + position: relative; + overflow: hidden; + min-height: 450px; + border-radius: 24px; + background: #e6ecdd; +} + +.map-illustration::before { + content: ""; + position: absolute; + inset: 0; + opacity: 0.35; + background-image: linear-gradient(rgba(23, 48, 43, 0.08) 1px, transparent 1px), linear-gradient(90deg, rgba(23, 48, 43, 0.08) 1px, transparent 1px); + background-size: 42px 42px; +} + +.map-road { + position: absolute; + z-index: 1; + height: 20px; + border: 6px solid var(--white); + border-right: 0; + border-left: 0; + background: #d5d2c8; + transform-origin: center; +} + +.road-one { width: 130%; top: 120px; left: -15%; transform: rotate(22deg); } +.road-two { width: 120%; top: 270px; left: -10%; transform: rotate(-18deg); } +.road-three { width: 105%; top: 170px; left: -15%; transform: rotate(80deg); } + +.map-water { + position: absolute; + z-index: 2; + width: 130%; + height: 50px; + right: -30%; + bottom: 65px; + border: 8px solid rgba(255, 255, 255, 0.62); + border-right: 0; + border-left: 0; + background: #9dcad0; + transform: rotate(-12deg); +} + +.map-park { + position: absolute; + border-radius: 50%; + background: #b9d0a7; +} + +.park-one { width: 190px; height: 140px; top: -30px; right: -40px; } +.park-two { width: 140px; height: 140px; bottom: 70px; left: -50px; } + +.map-pin { + position: absolute; + z-index: 5; + top: 175px; + left: 53%; + width: 56px; + height: 56px; + border: 7px solid var(--white); + border-radius: 50% 50% 50% 6px; + background: var(--coral-600); + box-shadow: 0 10px 22px rgba(23, 48, 43, 0.18); + transform: rotate(-45deg); +} + +.map-pin i { + position: absolute; + width: 13px; + height: 13px; + top: 14px; + left: 14px; + border-radius: 50%; + background: var(--white); +} + +.map-label { + position: absolute; + z-index: 5; + top: 246px; + left: 45%; + padding: 7px 11px; + border-radius: 8px; + background: var(--green-900); + color: var(--white); + font-size: 0.72rem; + font-weight: 800; +} + +.map-river-label { + position: absolute; + z-index: 4; + right: 20px; + bottom: 76px; + color: #3c7f89; + font-family: var(--font-display); + font-size: 1rem; + font-style: italic; + transform: rotate(-12deg); +} + +.map-footer { + display: flex; + min-height: 92px; + align-items: center; + justify-content: space-between; + gap: 20px; + padding: 15px 12px 5px 16px; +} + +.map-footer > div { + display: flex; + flex-direction: column; +} + +.map-footer strong { + font-size: 0.86rem; +} + +.map-footer span { + color: var(--ink-soft); + font-size: 0.7rem; +} + +.site-footer { + background: var(--green-950); + color: var(--white); +} + +.footer-top { + display: grid; + min-height: 170px; + grid-template-columns: 1fr 1fr auto; + align-items: center; + gap: 40px; + border-bottom: 1px solid rgba(255, 255, 255, 0.12); +} + +.brand-footer .brand-mark { + background: var(--sun-500); +} + +.brand-footer .brand-roof { + border-color: var(--green-950); +} + +.brand-footer .brand-door { + border-color: var(--green-950); +} + +.brand-footer .brand-copy span { + color: rgba(255, 255, 255, 0.62); +} + +.footer-top > p { + max-width: 340px; + color: rgba(255, 255, 255, 0.62); + font-size: 0.82rem; +} + +.footer-links { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 60px; + padding-top: 54px; + padding-bottom: 54px; +} + +.footer-links > div { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 8px; +} + +.footer-links strong { + margin-bottom: 9px; + color: var(--sun-500); + font-size: 0.67rem; + letter-spacing: 0.12em; + text-transform: uppercase; +} + +.footer-links a, +.footer-links span { + color: rgba(255, 255, 255, 0.68); + font-size: 0.78rem; + transition-property: color; + transition-duration: 160ms; +} + +.footer-links a:hover { + color: var(--white); +} + +.footer-bottom { + display: flex; + min-height: 70px; + align-items: center; + justify-content: space-between; + border-top: 1px solid rgba(255, 255, 255, 0.12); + color: rgba(255, 255, 255, 0.5); + font-size: 0.67rem; +} + +.footer-bottom div { + display: flex; + gap: 22px; +} + +.detail-dialog { + width: min(660px, calc(100vw - 32px)); + max-height: min(760px, calc(100vh - 32px)); + padding: 0; + overflow: visible; + border: 0; + border-radius: 28px; + background: var(--cream-50); + color: var(--ink); + box-shadow: 0 32px 90px rgba(0, 24, 20, 0.32); +} + +.detail-dialog::backdrop { + background: rgba(6, 42, 35, 0.72); + backdrop-filter: blur(5px); +} + +.detail-dialog[open] { + animation: dialog-in 240ms cubic-bezier(0.2, 0, 0, 1) both; +} + +@keyframes dialog-in { + from { opacity: 0; transform: translateY(12px); filter: blur(4px); } + to { opacity: 1; transform: translateY(0); filter: blur(0); } +} + +.dialog-shell { + position: relative; + max-height: min(760px, calc(100vh - 32px)); + overflow: auto; + padding: 48px; +} + +.dialog-close { + position: absolute; + top: 18px; + right: 18px; + display: grid; + width: 44px; + height: 44px; + place-items: center; + border: 0; + border-radius: 13px; + background: var(--cream-100); + color: var(--green-900); + cursor: pointer; + transition-property: background-color, scale; + transition-duration: 160ms; +} + +.dialog-close:hover { + background: var(--green-100); +} + +.dialog-close svg { + width: 22px; + height: 22px; +} + +.dialog-kicker { + color: var(--coral-600); + font-size: 0.68rem; + font-weight: 850; + letter-spacing: 0.14em; + text-transform: uppercase; +} + +.detail-dialog h2 { + max-width: 510px; + margin-top: 10px; + font-size: clamp(2rem, 5vw, 3.15rem); +} + +.dialog-content { + display: grid; + gap: 14px; + margin-top: 24px; + color: var(--ink-soft); + font-size: 0.92rem; +} + +.dialog-content ul { + display: grid; + gap: 8px; + margin: 4px 0; + padding-left: 20px; +} + +.dialog-content strong { + color: var(--ink); +} + +.dialog-note { + padding: 16px; + border-radius: 14px; + background: var(--sun-100); + color: var(--ink); + font-size: 0.78rem; +} + +.dialog-actions { + display: flex; + flex-wrap: wrap; + gap: 10px; + margin-top: 28px; +} + +.legal-body { + min-height: 100vh; +} + +.legal-header { + background: var(--green-950); + color: var(--white); +} + +.legal-header .header-inner { + justify-content: space-between; +} + +.legal-main { + padding: 80px 0 110px; +} + +.legal-content { + max-width: 780px; +} + +.legal-content h1 { + font-size: clamp(3rem, 7vw, 5rem); +} + +.legal-content h2 { + margin-top: 44px; + font-family: var(--font-sans); + font-size: 1.2rem; + font-weight: 800; + letter-spacing: -0.02em; +} + +.legal-content p, +.legal-content ul { + margin: 14px 0 0; + color: var(--ink-soft); +} + +.legal-content a { + color: var(--green-900); + font-weight: 700; + text-decoration: underline; + text-underline-offset: 3px; +} + +.legal-note { + margin-top: 32px !important; + padding: 20px; + border-radius: 16px; + background: var(--sun-100); + color: var(--ink) !important; + font-size: 0.82rem; +} + +.reveal { + opacity: 0; + transform: translateY(14px); + filter: blur(4px); + transition-property: opacity, transform, filter; + transition-duration: 560ms; + transition-delay: var(--delay, 0ms); + transition-timing-function: cubic-bezier(0.2, 0, 0, 1); +} + +.reveal.is-visible { + opacity: 1; + transform: translateY(0); + filter: blur(0); +} + +:focus-visible { + outline: 3px solid var(--sun-500); + outline-offset: 3px; +} + +@media (max-width: 1050px) { + .desktop-nav { + display: none; + } + + .header-contact { + margin-left: auto; + } + + .menu-button { + display: grid; + } + + .hero-grid { + grid-template-columns: 1fr 0.95fr; + gap: 44px; + } + + .hero h1 { + font-size: clamp(3.1rem, 6vw, 4.6rem); + } + + .quick-grid { + grid-template-columns: repeat(3, 1fr); + } + + .profile-grid { + grid-template-columns: 1fr 1fr; + } + + .profile-card:last-child { + grid-column: span 2; + min-height: 390px; + } + + .story-grid { + grid-template-columns: 1fr 1fr; + grid-template-rows: 340px 340px 280px; + } + + .story-large { + grid-row: span 2; + } + + .story-wide { + grid-column: span 2; + } + + .contact-grid { + grid-template-columns: 0.92fr 1.08fr; + gap: 48px; + } +} + +@media (max-width: 820px) { + :root { + --shell: min(100% - 32px, 680px); + } + + .section { + padding: 84px 0; + } + + .utility-inner span { + display: none; + } + + .utility-inner { + justify-content: flex-end; + } + + .hero-grid { + grid-template-columns: 1fr; + padding-top: 64px; + padding-bottom: 112px; + } + + .hero-copy { + max-width: 650px; + } + + .hero-visual { + width: min(100%, 560px); + margin-inline: auto; + } + + .hero-image-wrap { + aspect-ratio: 1.15; + border-radius: 130px 28px 28px 28px; + } + + .sticker-move { + left: -8px; + } + + .quick-heading { + align-items: start; + flex-direction: column; + gap: 14px; + } + + .quick-grid { + grid-template-columns: 1fr 1fr; + } + + .quick-card:last-child { + grid-column: span 2; + } + + .profile-grid, + .community-grid { + grid-template-columns: 1fr; + } + + .profile-card, + .profile-card:last-child { + grid-column: auto; + min-height: 430px; + } + + .place-grid, + .parents-grid, + .contact-grid { + grid-template-columns: 1fr; + } + + .place-visual { + min-height: 570px; + } + + .place-image-main { + height: 500px; + } + + .section-heading-split { + grid-template-columns: 1fr; + gap: 20px; + } + + .story-grid { + grid-template-columns: 1fr 1fr; + } + + .parents-intro { + position: static; + } + + .parents-intro > p:not(.eyebrow) { + max-width: 560px; + } + + .parents-note { + max-width: 390px; + } + + .contact-grid { + gap: 60px; + } + + .map-card { + max-width: 620px; + } + + .footer-top { + grid-template-columns: 1fr auto; + padding: 34px 0; + } + + .footer-top > p { + display: none; + } +} + +@media (max-width: 600px) { + :root { + --shell: calc(100vw - 28px); + } + + .header-inner { + min-height: 70px; + } + + .brand-mark { + width: 43px; + height: 43px; + border-radius: 13px; + } + + .brand-copy strong { + font-size: 1.14rem; + } + + .brand-copy span { + font-size: 0.58rem; + } + + .header-contact { + display: none; + } + + .menu-button { + margin-left: auto; + } + + .hero-grid { + padding-top: 52px; + } + + .hero h1 { + font-size: clamp(2.9rem, 14vw, 4rem); + } + + .hero-lead { + margin-top: 22px; + } + + .hero-actions { + align-items: flex-start; + flex-direction: column; + gap: 10px; + } + + .hero-signals { + display: grid; + margin-top: 34px; + } + + .hero-visual { + padding: 22px 10px 10px 2px; + } + + .hero-image-wrap { + aspect-ratio: 0.95; + border-radius: 100px 22px 22px 22px; + } + + .sticker-year { + right: -5px; + width: 100px; + height: 100px; + } + + .sticker-year strong { + font-size: 1.65rem; + } + + .sticker-move { + bottom: 40px; + } + + .quick-section { + padding-top: 54px; + } + + .quick-grid { + grid-template-columns: 1fr; + } + + .quick-card, + .quick-card:last-child { + min-height: 106px; + grid-column: auto; + flex-direction: row; + align-items: center; + justify-content: flex-start; + gap: 15px; + padding: 16px; + border-radius: 18px; + } + + .quick-arrow { + top: 50%; + bottom: auto; + transform: translateY(-50%); + } + + .quick-card:hover .quick-arrow { + transform: translate(3px, -50%); + } + + .section-heading h2, + .place-copy h2, + .parents-intro h2, + .contact-copy h2 { + font-size: 2.65rem; + } + + .profile-card, + .profile-card:last-child { + min-height: 460px; + padding: 26px; + border-radius: 24px; + } + + .place-visual { + min-height: 490px; + } + + .place-image-main { + width: 88%; + height: 430px; + border-radius: 90px 20px 20px 20px; + } + + .place-image-small { + width: 45%; + border-width: 7px; + border-radius: 22px; + } + + .place-caption { + bottom: 30px; + left: 14px; + font-size: 0.78rem; + } + + .place-facts div { + grid-template-columns: 100px 1fr; + } + + .story-grid { + display: grid; + grid-template-columns: 1fr; + grid-template-rows: repeat(4, 360px); + } + + .story-large, + .story-wide { + grid-row: auto; + grid-column: auto; + } + + .story-wide { + flex-direction: column; + align-items: stretch; + } + + .story-art-track { + right: -20px; + bottom: 80px; + } + + .story-art-letters { + height: 240px; + } + + .story-art-letters span { + width: 78px; + height: 92px; + font-size: 3.4rem; + } + + .community-card { + min-height: 325px; + padding: 27px; + } + + .info-accordion summary { + min-height: 76px; + grid-template-columns: 34px 1fr 24px; + font-size: 1.08rem; + } + + .accordion-content { + padding-right: 10px; + padding-left: 44px; + } + + .map-illustration { + min-height: 390px; + } + + .map-footer { + align-items: stretch; + flex-direction: column; + padding-bottom: 10px; + } + + .map-footer .button { + width: 100%; + } + + .footer-top { + display: flex; + align-items: flex-start; + flex-direction: column; + gap: 24px; + } + + .footer-links { + grid-template-columns: 1fr 1fr; + gap: 42px 24px; + } + + .footer-links > div:last-child { + grid-column: span 2; + } + + .footer-bottom { + align-items: flex-start; + flex-direction: column; + justify-content: center; + gap: 8px; + padding: 16px 0; + } + + .dialog-shell { + padding: 40px 24px 28px; + } +} + +@media (prefers-reduced-motion: reduce) { + html { + scroll-behavior: auto; + } + + *, + *::before, + *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + } + + .reveal { + opacity: 1; + transform: none; + filter: none; + } +}