diff --git a/app/modules/loyalty/locales/de.json b/app/modules/loyalty/locales/de.json
index 24c2a3bb..61fb24c8 100644
--- a/app/modules/loyalty/locales/de.json
+++ b/app/modules/loyalty/locales/de.json
@@ -411,6 +411,9 @@
"terms_cms_page_hint": "Geben Sie einen CMS-Seiten-Slug ein (z.B. agb) um die vollständigen AGB aus dem CMS-Modul anzuzeigen",
"terms_conditions": "Allgemeine Geschäftsbedingungen (Fallback)",
"terms_fallback_hint": "Wird verwendet wenn kein CMS-Slug gesetzt ist",
+ "terms_text_hint": "Klartext-Fallback. Entweder dieses Feld ODER der CMS-Seiten-Slug oben ist erforderlich, damit Kunden die AGB auf der Anmeldeseite lesen können.",
+ "terms_required_warning": "Kunden müssen Ihre AGB lesen können, bevor sie diese akzeptieren. Füllen Sie entweder den CMS-Seiten-Slug oben oder den Klartext-Fallback unten aus — bis dahin ist der \"AGB\"-Link auf der Anmeldeseite des Storefronts nicht klickbar.",
+ "terms_required_tooltip": "Füllen Sie den CMS-Slug oder den Klartext der AGB aus, bevor Sie speichern.",
"privacy_policy_url": "Datenschutzrichtlinien-URL",
"program_status": "Programmstatus",
"program_active": "Programm aktiv",
diff --git a/app/modules/loyalty/locales/en.json b/app/modules/loyalty/locales/en.json
index 5bed301e..631f3cec 100644
--- a/app/modules/loyalty/locales/en.json
+++ b/app/modules/loyalty/locales/en.json
@@ -415,6 +415,9 @@
"terms_cms_page_hint": "Enter a CMS page slug (e.g. terms-and-conditions) to display full T&C from the CMS module",
"terms_conditions": "Terms & Conditions (fallback)",
"terms_fallback_hint": "Used when no CMS page slug is set",
+ "terms_text_hint": "Plain-text fallback. Either this field OR the CMS page slug above is required so customers can read the terms on the enrollment page.",
+ "terms_required_warning": "Customers must be able to read your terms before accepting them. Fill in either the CMS page slug above or the plain-text fallback below — until you do, the 'Terms & Conditions' link on the storefront enrollment page is not clickable.",
+ "terms_required_tooltip": "Fill in either the CMS page slug or the plain-text terms before saving.",
"privacy_policy_url": "Privacy Policy URL",
"program_status": "Program Status",
"program_active": "Program Active",
diff --git a/app/modules/loyalty/locales/fr.json b/app/modules/loyalty/locales/fr.json
index 5102fe43..7ea73081 100644
--- a/app/modules/loyalty/locales/fr.json
+++ b/app/modules/loyalty/locales/fr.json
@@ -411,6 +411,9 @@
"terms_cms_page_hint": "Entrez un slug de page CMS (ex. conditions-generales) pour afficher les CGV complètes depuis le module CMS",
"terms_conditions": "Conditions Générales (secours)",
"terms_fallback_hint": "Utilisé quand aucun slug CMS n'est défini",
+ "terms_text_hint": "Texte de secours. Ce champ OU le slug CMS ci-dessus est requis afin que les clients puissent lire les conditions sur la page d'inscription.",
+ "terms_required_warning": "Les clients doivent pouvoir lire vos conditions avant de les accepter. Remplissez soit le slug de page CMS ci-dessus, soit le texte de secours ci-dessous — tant que ce n'est pas fait, le lien « Conditions Générales » sur la page d'inscription du storefront n'est pas cliquable.",
+ "terms_required_tooltip": "Remplissez le slug CMS ou le texte des conditions avant d'enregistrer.",
"privacy_policy_url": "URL politique de confidentialité",
"program_status": "Statut du programme",
"program_active": "Programme actif",
diff --git a/app/modules/loyalty/locales/lb.json b/app/modules/loyalty/locales/lb.json
index f56c67ab..95f61476 100644
--- a/app/modules/loyalty/locales/lb.json
+++ b/app/modules/loyalty/locales/lb.json
@@ -411,6 +411,9 @@
"terms_cms_page_hint": "Gitt e CMS-Säiten-Slug an (z.B. agb) fir déi komplett AGB vum CMS-Modul unzeweisen",
"terms_conditions": "Allgemeng Geschäftsbedingungen (Fallback)",
"terms_fallback_hint": "Gëtt benotzt wann keen CMS-Slug gesat ass",
+ "terms_text_hint": "Plain-Text-Ersatz. Entweder dëst Feld ODER de CMS-Säit-Slug uewendriwwer ass erfuerderlech, fir datt Clienten d'AGB op der Aschreiwungssäit liesen kënnen.",
+ "terms_required_warning": "Clienten musse fäeg sinn Är AGB ze liese ier se se akzeptéieren. Fëllt entweder de CMS-Säit-Slug uewendriwwer oder de Plain-Text-Ersatz hei drënner aus — bis dat gemaach ass, ass de \"AGB\"-Link op der Aschreiwungssäit vum Storefront net cliquéierbar.",
+ "terms_required_tooltip": "Fëllt de CMS-Slug oder den AGB-Plain-Text aus ier Dir späichert.",
"privacy_policy_url": "Dateschutzrichtlinn-URL",
"program_status": "Programmstatus",
"program_active": "Programm aktiv",
diff --git a/app/modules/loyalty/templates/loyalty/shared/program-form.html b/app/modules/loyalty/templates/loyalty/shared/program-form.html
index 23a87c5a..ef9ca121 100644
--- a/app/modules/loyalty/templates/loyalty/shared/program-form.html
+++ b/app/modules/loyalty/templates/loyalty/shared/program-form.html
@@ -245,6 +245,22 @@
{{ _('loyalty.shared.program_form.terms_privacy') }}
+
+ {# Warning banner — visible only when neither terms field is filled.
+ The storefront enrollment page renders the "Terms & Conditions" link
+ as a non-clickable in that case (see enroll.html:122-124),
+ so customers can't read the terms before accepting. #}
+
+