Four pages: /imprint/ and /privacy/ in English, /de/impressum/ and /de/datenschutz/ in German, linked from the footer of the matching language. The German version is the authoritative one; the English one says so. Every fact in them was checked rather than assumed. The hosting section comes from the Art. 28 processing agreement with Hetzner (EU/EEA only, DPO appointed, breach notification, ISO 27001, BSI C5 Type 2); the server location comes from the provider's API and is Nuremberg; the "no cookies, no third-party requests, nothing in your browser" claim comes from loading the live page in a browser that records every outgoing request — all of them went to this domain, with zero cookies and an empty localStorage. nginx now logs without the client address. The default format was writing $remote_addr and X-Forwarded-For, so a static page that needs no personal data at all was storing the IP of everyone who looked at it. The log keeps time, request, status, size, referrer and user agent — enough to operate the site, minus the field that identifies a person. Data minimisation beats a retention policy you then have to honour. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nh4A79bbqT9dcd2inzYUdg
78 lines
2.3 KiB
Plaintext
78 lines
2.3 KiB
Plaintext
---
|
|
import '@fontsource/space-grotesk/400.css';
|
|
import '@fontsource/space-grotesk/500.css';
|
|
import '@fontsource/space-grotesk/700.css';
|
|
import '@fontsource/space-mono/400.css';
|
|
import '@fontsource/space-mono/700.css';
|
|
import '../styles/tokens.css';
|
|
import '../styles/site.css';
|
|
import type { LegalPage } from '../lib/legal';
|
|
|
|
interface Props {
|
|
page: LegalPage;
|
|
lang: 'en' | 'de';
|
|
canonical: string;
|
|
otherHref: string;
|
|
otherLabel: string;
|
|
backHref: string;
|
|
backLabel: string;
|
|
siblingHref: string;
|
|
siblingLabel: string;
|
|
}
|
|
const { page, lang, canonical, otherHref, otherLabel, backHref, backLabel, siblingHref, siblingLabel } = Astro.props;
|
|
const home = lang === 'de' ? '/de/' : '/';
|
|
---
|
|
|
|
<!doctype html>
|
|
<html lang={lang}>
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
|
<meta name="theme-color" content="#EAEAE3" />
|
|
<title>{page.title} · Klarbild</title>
|
|
<meta name="robots" content="noindex, follow" />
|
|
<link rel="canonical" href={canonical} />
|
|
</head>
|
|
<body>
|
|
<header class="top">
|
|
<div class="shell top-in">
|
|
<a class="brand" href={home}><span class="regmark"></span>klarbild</a>
|
|
<nav>
|
|
<a href={backHref}>{backLabel}</a>
|
|
<a class="langswitch" href={otherHref} hreflang={otherLabel.toLowerCase()}>{otherLabel}</a>
|
|
</nav>
|
|
</div>
|
|
</header>
|
|
|
|
<main class="legal shell">
|
|
<span class="kicker">{page.updated}</span>
|
|
<h1>{page.title}</h1>
|
|
{page.intro && <p class="lead">{page.intro}</p>}
|
|
|
|
{page.blocks.map((b) => (
|
|
<section class="lblock">
|
|
{b.h && <h2>{b.h}</h2>}
|
|
{b.rows && (
|
|
<dl class="lrows">
|
|
{b.rows.map(([k, v]) => (<><dt>{k}</dt><dd>{v}</dd></>))}
|
|
</dl>
|
|
)}
|
|
{b.p && <p>{b.p}</p>}
|
|
{b.html && <p set:html={b.html} />}
|
|
</section>
|
|
))}
|
|
|
|
<p class="lsibling"><a href={siblingHref}>{siblingLabel}</a></p>
|
|
</main>
|
|
|
|
<footer>
|
|
<div class="shell foot-in">
|
|
<a class="brand" href={home}><span class="regmark"></span>klarbild</a>
|
|
<a href={backHref}>{backLabel}</a>
|
|
<a href={siblingHref}>{siblingLabel}</a>
|
|
<a href="https://github.com/tillheidrich/klarbild" rel="noopener">GitHub</a>
|
|
</div>
|
|
</footer>
|
|
</body>
|
|
</html>
|