diff --git a/apps/frontend/src/components/HealthConsentModal.css b/apps/frontend/src/components/HealthConsentModal.css
new file mode 100644
index 0000000..3c76868
--- /dev/null
+++ b/apps/frontend/src/components/HealthConsentModal.css
@@ -0,0 +1,8 @@
+.health-consent-modal { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 2rem 2.25rem 1.75rem; width: 100%; max-width: 360px; box-shadow: 0 20px 60px rgba(28, 25, 23, 0.18); animation: slideUp 0.18s ease; }
+.health-consent-title { font-size: 1.15rem; font-weight: 700; color: var(--text-main); margin: 0 0 0.75rem; }
+.health-consent-desc { font-size: 0.9rem; color: var(--text-muted); line-height: 1.6; margin: 0 0 1.5rem; }
+.health-consent-actions { display: flex; flex-direction: column; gap: 0.5rem; }
+.health-consent-btn { width: 100%; padding: 0.65rem 1rem; border-radius: 999px; border: none; font-size: 0.9rem; font-weight: 600; cursor: pointer; transition: opacity 0.15s; }
+.health-consent-btn:hover { opacity: 0.85; }
+.health-consent-btn--accept { background: var(--primary); color: var(--on-primary); }
+.health-consent-btn--cancel { background: var(--surface-muted); color: var(--text-main); border: 1px solid var(--border); }
diff --git a/apps/frontend/src/components/HealthConsentModal.jsx b/apps/frontend/src/components/HealthConsentModal.jsx
new file mode 100644
index 0000000..24da0db
--- /dev/null
+++ b/apps/frontend/src/components/HealthConsentModal.jsx
@@ -0,0 +1,28 @@
+import React, { useEffect } from 'react';
+import { useTranslation } from '../i18n';
+import './HealthConsentModal.css';
+
+function HealthConsentModal({ onAccept, onCancel }) {
+ const { t } = useTranslation();
+
+ useEffect(() => {
+ function handleKey(e) { if (e.key === 'Escape') onCancel(); }
+ document.addEventListener('keydown', handleKey);
+ return () => document.removeEventListener('keydown', handleKey);
+ }, [onCancel]);
+
+ return (
+
+
e.stopPropagation()} role="dialog" aria-modal="true" aria-label={t('health_consent.title')}>
+
{t('health_consent.title')}
+
{t('health_consent.description')}
+
+
+
+
+
+
+ );
+}
+
+export default HealthConsentModal;
diff --git a/apps/frontend/src/views/PrivacyView.css b/apps/frontend/src/views/PrivacyView.css
new file mode 100644
index 0000000..cf32582
--- /dev/null
+++ b/apps/frontend/src/views/PrivacyView.css
@@ -0,0 +1,14 @@
+.privacy-view { width: 100%; max-width: 640px; margin: 0 auto; padding: 1rem 1.25rem 2rem; animation: fadeInUp 0.3s ease-out; }
+.privacy-header { display: flex; align-items: center; gap: 0.75rem; margin-bottom: 1.5rem; }
+.privacy-back { background: var(--surface-muted); border: 1px solid var(--border); border-radius: var(--radius); width: 36px; height: 36px; display: flex; align-items: center; justify-content: center; cursor: pointer; font-size: 1.1rem; color: var(--text-main); flex-shrink: 0; transition: background 0.15s; }
+.privacy-back:hover { background: var(--border); }
+.privacy-title { font-size: 1.3rem; font-weight: 700; color: var(--text-main); margin: 0; }
+.privacy-updated { font-size: 0.8rem; color: var(--text-muted); margin: 0 0 1.5rem; }
+.privacy-content { display: flex; flex-direction: column; gap: 1.5rem; }
+.privacy-section { background: var(--surface-muted); border-radius: var(--radius); padding: 1.25rem; }
+.privacy-section-title { font-size: 1rem; font-weight: 700; color: var(--text-main); margin: 0 0 0.75rem; }
+.privacy-section-content { font-size: 0.88rem; color: var(--text-muted); line-height: 1.6; }
+.privacy-section-content p { margin: 0 0 0.5rem; }
+.privacy-section-content p:last-child { margin-bottom: 0; }
+@keyframes fadeInUp { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
+@media (max-width: 768px) { .privacy-view { padding: 0.75rem 1rem 2rem; } }
diff --git a/apps/frontend/src/views/PrivacyView.jsx b/apps/frontend/src/views/PrivacyView.jsx
new file mode 100644
index 0000000..8ee184e
--- /dev/null
+++ b/apps/frontend/src/views/PrivacyView.jsx
@@ -0,0 +1,32 @@
+import React from 'react';
+import { useTranslation } from '../i18n';
+import './PrivacyView.css';
+
+function PrivacyView({ onBack }) {
+ const { t } = useTranslation();
+ const sections = ['controller', 'data_collected', 'purpose', 'legal_basis', 'external_services', 'retention', 'rights', 'contact', 'cookies'];
+
+ return (
+
+
+
+
{t('privacy.title')}
+
+
+
{t('privacy.last_updated')}
+ {sections.map(section => (
+
+ {t(`privacy.section.${section}.title`)}
+
+ {t(`privacy.section.${section}.content`).split('\n').map((line, i) => (
+
{line}
+ ))}
+
+
+ ))}
+
+
+ );
+}
+
+export default PrivacyView;