diff --git a/conf/template_settings.py b/conf/template_settings.py
index 0cafdf0a..d822775f 100644
--- a/conf/template_settings.py
+++ b/conf/template_settings.py
@@ -62,6 +62,7 @@
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
"docs.utils.context_processors.docs_current_path",
+ "core.utils.generic_functions.cookie_consent",
],
},
},
diff --git a/core/config.py b/core/config.py
index 975badb7..87404ccc 100644
--- a/core/config.py
+++ b/core/config.py
@@ -161,3 +161,8 @@
"Submitter": "submitting_institution",
"Collector": "lab_code_1",
}
+
+# Cookie consent
+COOKIE_CONSENT_NAME = "relecovCookieConsent"
+COOKIE_CONSENT_MAX_AGE = 60 * 60 * 24 * 365
+COOKIE_CONSENT_VALUES = {"all", "necessary_only"}
diff --git a/core/static/core/custom/css/cookie_consent.css b/core/static/core/custom/css/cookie_consent.css
new file mode 100644
index 00000000..98b8df30
--- /dev/null
+++ b/core/static/core/custom/css/cookie_consent.css
@@ -0,0 +1,259 @@
+.cookie-consent,
+.cookie-modal {
+ font-family: var(--font-primary);
+}
+
+.cookie-consent-hidden {
+ display: none !important;
+}
+
+.cookie-consent {
+ position: fixed;
+ right: 24px;
+ bottom: 24px;
+ left: 24px;
+ z-index: 1200;
+}
+
+.cookie-consent-content {
+ display: flex;
+ gap: 24px;
+ align-items: center;
+ max-width: 1180px;
+ margin: 0 auto;
+ padding: 24px;
+ color: var(--color-default);
+ background: var(--color-white);
+ border: 1px solid rgba(var(--color-secondary-rgb), 0.25);
+ border-radius: 8px;
+ box-shadow: 0 12px 40px rgba(var(--color-black-rgb), 0.22);
+}
+
+.cookie-consent h2,
+.cookie-modal h2 {
+ margin: 0 0 12px;
+ color: var(--color-primary);
+ font-weight: 700;
+}
+
+.cookie-consent p,
+.cookie-modal p {
+ margin: 0 0 10px;
+ line-height: 1.55;
+}
+
+.cookie-consent-actions,
+.cookie-modal-actions {
+ display: flex;
+ gap: 12px;
+ flex-shrink: 0;
+ justify-content: flex-end;
+}
+
+.cookie-consent-actions form,
+.cookie-modal-actions form {
+ margin: 0;
+}
+
+.cookie-btn {
+ display: inline-flex;
+ min-width: 128px;
+ min-height: 46px;
+ align-items: center;
+ justify-content: center;
+ padding: 11px 18px;
+ border: 1px solid var(--color-primary);
+ border-radius: 6px;
+ font-weight: 700;
+ text-align: center;
+ text-decoration: none;
+ transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease;
+}
+
+.cookie-btn-primary,
+.cookie-btn-secondary:hover,
+.cookie-btn-outline:hover {
+ color: var(--color-white);
+ background: var(--color-primary);
+}
+
+.cookie-btn-secondary {
+ color: var(--color-primary);
+ background: var(--color-secondary);
+}
+
+.cookie-btn-primary:hover,
+.cookie-btn-secondary:hover,
+.cookie-btn-outline:hover {
+ text-decoration: none;
+}
+
+.cookie-btn-outline {
+ color: var(--color-primary);
+ background: var(--color-white);
+}
+
+.cookie-modal .modal-dialog {
+ max-width: min(1170px, calc(100vw - 36px));
+}
+
+.cookie-modal-panel {
+ position: relative;
+ display: grid;
+ grid-template-columns: 38% 62%;
+ width: 100%;
+ min-height: 600px;
+ overflow: hidden;
+ background: var(--color-white);
+ border: 0;
+ border-radius: 6px;
+ box-shadow: 0 24px 70px rgba(var(--color-black-rgb), 0.35);
+}
+
+.cookie-modal-close {
+ position: absolute;
+ top: 0;
+ right: 0;
+ display: inline-flex;
+ width: 60px;
+ height: 60px;
+ align-items: center;
+ justify-content: center;
+ color: var(--color-white);
+ background: var(--color-primary);
+ border: 0;
+ border-bottom-left-radius: 30px;
+ font-size: 22px;
+ text-decoration: none;
+ z-index: 2;
+}
+
+.cookie-modal-sidebar {
+ padding: 44px 60px;
+ background: var(--color-white);
+}
+
+.cookie-modal-logo {
+ width: 150px;
+ height: auto;
+ margin-bottom: 28px;
+}
+
+.cookie-tab {
+ display: block;
+ width: 100%;
+ margin-bottom: 14px;
+ padding: 14px 20px;
+ color: var(--color-primary);
+ text-align: left;
+ text-decoration: none;
+ text-transform: uppercase;
+ background: var(--color-white);
+ border: 1px solid rgba(var(--color-secondary-rgb), 0.35);
+ border-radius: 5px;
+ font-weight: 700;
+}
+
+.cookie-tab:hover {
+ color: var(--color-primary);
+}
+
+.cookie-tab.active {
+ background: #f0f0f0;
+}
+
+.cookie-modal-body {
+ display: flex;
+ flex-direction: column;
+ padding: 44px 60px 38px;
+ background: #f7f7f7;
+}
+
+.cookie-tab-panel {
+ display: none;
+}
+
+.cookie-tab-panel.active {
+ display: block;
+}
+
+.cookie-table-wrapper {
+ margin-top: 20px;
+ overflow-x: auto;
+}
+
+.cookie-table {
+ width: 100%;
+ color: var(--color-default);
+ background: var(--color-white);
+ border-collapse: collapse;
+ font-size: 0.92rem;
+}
+
+.cookie-table th,
+.cookie-table td {
+ padding: 10px 12px;
+ border: 1px solid rgba(var(--color-secondary-rgb), 0.25);
+ text-align: left;
+ vertical-align: top;
+}
+
+.cookie-table th {
+ color: var(--color-primary);
+ font-weight: 700;
+}
+
+.cookie-toggle-row {
+ display: flex;
+ gap: 12px;
+ align-items: center;
+ margin-top: 24px;
+ color: #70b77e;
+}
+
+.cookie-toggle {
+ position: relative;
+ display: inline-block;
+ width: 52px;
+ height: 30px;
+ background: #8c8c8c;
+ border-radius: 999px;
+}
+
+.cookie-toggle::after {
+ position: absolute;
+ top: 2px;
+ right: 2px;
+ width: 26px;
+ height: 26px;
+ content: "";
+ background: var(--color-white);
+ border-radius: 50%;
+ box-shadow: 0 1px 4px rgba(var(--color-black-rgb), 0.3);
+}
+
+.cookie-modal-actions {
+ margin-top: auto;
+ padding-top: 32px;
+ border-top: 1px solid rgba(var(--color-gray-rgb), 0.35);
+}
+
+@media (max-width: 991px) {
+ .cookie-consent-content,
+ .cookie-consent-actions,
+ .cookie-modal-actions {
+ flex-direction: column;
+ align-items: stretch;
+ }
+
+ .cookie-modal-panel {
+ display: block;
+ max-height: calc(100vh - 36px);
+ overflow-y: auto;
+ }
+
+ .cookie-modal-sidebar,
+ .cookie-modal-body {
+ padding: 28px;
+ }
+}
diff --git a/core/static/core/custom/img/GDPR.jpg b/core/static/core/custom/img/GDPR.jpg
new file mode 100644
index 00000000..8be61b8e
Binary files /dev/null and b/core/static/core/custom/img/GDPR.jpg differ
diff --git a/core/templates/core/base.html b/core/templates/core/base.html
index 2c1acde1..b14f35b8 100644
--- a/core/templates/core/base.html
+++ b/core/templates/core/base.html
@@ -26,6 +26,7 @@
+