fix(privacy): self-host Inter font, remove Google Fonts
All checks were successful
Build & Deploy to Staging / Build & Deploy to Staging (push) Successful in 19m23s

- Drops all fonts.googleapis.com / fonts.gstatic.com references
- Adds self-hosted woff2 under public/fonts/
- @font-face with font-display: swap
- Test asserts no external font refs in generated HTML

Closes GDPR contradiction: privacy policy promises 'no third-party tracking'
and 'EU-hosted' while every page was leaking visitor IPs to Google (Munich
District Court 2022 ruling, €100/visitor damages precedent).
This commit is contained in:
DocFast Subagent 2026-04-10 11:13:26 +02:00
parent 6ce773a071
commit a374a93937
21 changed files with 143 additions and 23 deletions

View file

@ -17,6 +17,12 @@
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>⚡</text></svg>">
<link rel="stylesheet" href="/swagger-ui/swagger-ui.css">
<style>
/* Self-hosted Inter font (GDPR: no third-party requests to Google) */
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 400; font-display: swap; src: url('/fonts/Inter-Regular.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 500; font-display: swap; src: url('/fonts/Inter-Medium.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 600; font-display: swap; src: url('/fonts/Inter-SemiBold.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 700; font-display: swap; src: url('/fonts/Inter-Bold.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 800; font-display: swap; src: url('/fonts/Inter-ExtraBold.woff2') format('woff2'); }
html { box-sizing: border-box; overflow-y: scroll; }
*, *:before, *:after { box-sizing: inherit; }
body { margin: 0; background: #1a1a2e; font-family: 'Inter', -apple-system, system-ui, sans-serif; }
@ -109,8 +115,6 @@
.skip-link { position: absolute; top: -100%; left: 16px; background: #34d399; color: #0b0d11; padding: 8px 16px; border-radius: 0 0 8px 8px; font-weight: 600; font-size: 0.9rem; z-index: 200; transition: top 0.2s; text-decoration: none; }
.skip-link:focus { top: 0; }
</style>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
</head>
<body>
<a href="#main" class="skip-link">Skip to content</a>

View file

@ -13,8 +13,13 @@
<meta name="twitter:image" content="https://docfast.dev/og-image.png">
<link rel="canonical" href="https://docfast.dev/examples">
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>⚡</text></svg>">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<style>
/* Self-hosted Inter font (GDPR: no third-party requests to Google) */
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 400; font-display: swap; src: url('/fonts/Inter-Regular.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 500; font-display: swap; src: url('/fonts/Inter-Medium.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 600; font-display: swap; src: url('/fonts/Inter-SemiBold.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 700; font-display: swap; src: url('/fonts/Inter-Bold.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 800; font-display: swap; src: url('/fonts/Inter-ExtraBold.woff2') format('woff2'); }
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--bg: #0b0d11; --bg2: #12151c; --fg: #e4e7ed; --muted: #7a8194;

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -13,8 +13,13 @@
<meta name="twitter:image" content="https://docfast.dev/og-image.png">
<link rel="canonical" href="https://docfast.dev/impressum">
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>⚡</text></svg>">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<style>
/* Self-hosted Inter font (GDPR: no third-party requests to Google) */
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 400; font-display: swap; src: url('/fonts/Inter-Regular.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 500; font-display: swap; src: url('/fonts/Inter-Medium.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 600; font-display: swap; src: url('/fonts/Inter-SemiBold.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 700; font-display: swap; src: url('/fonts/Inter-Bold.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 800; font-display: swap; src: url('/fonts/Inter-ExtraBold.woff2') format('woff2'); }
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--bg: #0b0d11; --bg2: #12151c; --fg: #e4e7ed; --muted: #7a8194;

View file

@ -68,6 +68,12 @@
</script>
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>⚡</text></svg>">
<style>
/* Self-hosted Inter font (GDPR: no third-party requests to Google) */
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 400; font-display: swap; src: url('/fonts/Inter-Regular.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 500; font-display: swap; src: url('/fonts/Inter-Medium.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 600; font-display: swap; src: url('/fonts/Inter-SemiBold.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 700; font-display: swap; src: url('/fonts/Inter-Bold.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 800; font-display: swap; src: url('/fonts/Inter-ExtraBold.woff2') format('woff2'); }
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--bg: #0b0d11; --bg2: #12151c; --fg: #e4e7ed; --muted: #7a8194;
@ -366,9 +372,6 @@ html, body {
.skip-link { position: absolute; top: -100%; left: 16px; background: var(--accent); color: #0b0d11; padding: 8px 16px; border-radius: 0 0 8px 8px; font-weight: 600; font-size: 0.9rem; z-index: 200; transition: top 0.2s; }
.skip-link:focus { top: 0; }
</style>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
</head>
<body>
<a href="#main" class="skip-link">Skip to content</a>
@ -595,9 +598,9 @@ html, body {
</footer>
<!-- Recovery Modal -->
<div class="modal-overlay" id="recoverModal" role="dialog" aria-label="Recover API key">
<div class="modal-overlay" id="recoverModal" role="dialog" aria-modal="true" aria-label="Recover API key">
<div class="modal">
<button class="close" id="btn-close-recover">&times;</button>
<button class="close" id="btn-close-recover" aria-label="Close">&times;</button>
<div id="recoverInitial" class="active">
<h2>Recover your API key</h2>
@ -639,9 +642,9 @@ html, body {
<!-- Email Change Modal -->
<div class="modal-overlay" id="emailChangeModal" role="dialog" aria-label="Change email">
<div class="modal-overlay" id="emailChangeModal" role="dialog" aria-modal="true" aria-label="Change email">
<div class="modal">
<button class="close" id="btn-close-email-change">&times;</button>
<button class="close" id="btn-close-email-change" aria-label="Close">&times;</button>
<div id="emailChangeInitial" class="active">
<h2>Change your email</h2>

View file

@ -1,4 +1,10 @@
<style>
/* Self-hosted Inter font (GDPR: no third-party requests to Google) */
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 400; font-display: swap; src: url('/fonts/Inter-Regular.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 500; font-display: swap; src: url('/fonts/Inter-Medium.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 600; font-display: swap; src: url('/fonts/Inter-SemiBold.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 700; font-display: swap; src: url('/fonts/Inter-Bold.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 800; font-display: swap; src: url('/fonts/Inter-ExtraBold.woff2') format('woff2'); }
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--bg: #0b0d11; --bg2: #12151c; --fg: #e4e7ed; --muted: #7a8194;

View file

@ -13,8 +13,13 @@
<meta name="twitter:image" content="https://docfast.dev/og-image.png">
<link rel="canonical" href="https://docfast.dev/privacy">
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>⚡</text></svg>">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<style>
/* Self-hosted Inter font (GDPR: no third-party requests to Google) */
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 400; font-display: swap; src: url('/fonts/Inter-Regular.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 500; font-display: swap; src: url('/fonts/Inter-Medium.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 600; font-display: swap; src: url('/fonts/Inter-SemiBold.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 700; font-display: swap; src: url('/fonts/Inter-Bold.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 800; font-display: swap; src: url('/fonts/Inter-ExtraBold.woff2') format('woff2'); }
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--bg: #0b0d11; --bg2: #12151c; --fg: #e4e7ed; --muted: #7a8194;

View file

@ -13,7 +13,6 @@
<meta name="twitter:image" content="https://docfast.dev/og-image.png">
<link rel="canonical" href="https://docfast.dev/examples">
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>⚡</text></svg>">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
{{> styles_base}}
<style>
.examples-hero { padding: 80px 0 40px; text-align: center; }

View file

@ -13,7 +13,6 @@
<meta name="twitter:image" content="https://docfast.dev/og-image.png">
<link rel="canonical" href="https://docfast.dev/impressum">
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>⚡</text></svg>">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
{{> styles_base}}
</head>
<body>

View file

@ -68,6 +68,12 @@
</script>
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>⚡</text></svg>">
<style>
/* Self-hosted Inter font (GDPR: no third-party requests to Google) */
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 400; font-display: swap; src: url('/fonts/Inter-Regular.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 500; font-display: swap; src: url('/fonts/Inter-Medium.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 600; font-display: swap; src: url('/fonts/Inter-SemiBold.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 700; font-display: swap; src: url('/fonts/Inter-Bold.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 800; font-display: swap; src: url('/fonts/Inter-ExtraBold.woff2') format('woff2'); }
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--bg: #0b0d11; --bg2: #12151c; --fg: #e4e7ed; --muted: #7a8194;
@ -366,9 +372,6 @@ html, body {
.skip-link { position: absolute; top: -100%; left: 16px; background: var(--accent); color: #0b0d11; padding: 8px 16px; border-radius: 0 0 8px 8px; font-weight: 600; font-size: 0.9rem; z-index: 200; transition: top 0.2s; }
.skip-link:focus { top: 0; }
</style>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
</head>
<body>
<a href="#main" class="skip-link">Skip to content</a>

View file

@ -13,7 +13,6 @@
<meta name="twitter:image" content="https://docfast.dev/og-image.png">
<link rel="canonical" href="https://docfast.dev/privacy">
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>⚡</text></svg>">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
{{> styles_base}}
</head>
<body>

View file

@ -13,7 +13,6 @@
<meta name="twitter:image" content="https://docfast.dev/og-image.png">
<link rel="canonical" href="https://docfast.dev/status">
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>⚡</text></svg>">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
{{> styles_base}}
<style>
.status-hero { text-align: center; padding: 48px 0 32px; }

View file

@ -13,7 +13,6 @@
<meta name="twitter:image" content="https://docfast.dev/og-image.png">
<link rel="canonical" href="https://docfast.dev/terms">
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>⚡</text></svg>">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
{{> styles_base}}
</head>
<body>

View file

@ -13,8 +13,13 @@
<meta name="twitter:image" content="https://docfast.dev/og-image.png">
<link rel="canonical" href="https://docfast.dev/status">
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>⚡</text></svg>">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<style>
/* Self-hosted Inter font (GDPR: no third-party requests to Google) */
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 400; font-display: swap; src: url('/fonts/Inter-Regular.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 500; font-display: swap; src: url('/fonts/Inter-Medium.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 600; font-display: swap; src: url('/fonts/Inter-SemiBold.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 700; font-display: swap; src: url('/fonts/Inter-Bold.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 800; font-display: swap; src: url('/fonts/Inter-ExtraBold.woff2') format('woff2'); }
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--bg: #0b0d11; --bg2: #12151c; --fg: #e4e7ed; --muted: #7a8194;

View file

@ -13,8 +13,13 @@
<meta name="twitter:image" content="https://docfast.dev/og-image.png">
<link rel="canonical" href="https://docfast.dev/terms">
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>⚡</text></svg>">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<style>
/* Self-hosted Inter font (GDPR: no third-party requests to Google) */
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 400; font-display: swap; src: url('/fonts/Inter-Regular.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 500; font-display: swap; src: url('/fonts/Inter-Medium.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 600; font-display: swap; src: url('/fonts/Inter-SemiBold.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 700; font-display: swap; src: url('/fonts/Inter-Bold.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 800; font-display: swap; src: url('/fonts/Inter-ExtraBold.woff2') format('woff2'); }
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--bg: #0b0d11; --bg2: #12151c; --fg: #e4e7ed; --muted: #7a8194;