diff --git a/src/crates/monolith-server/src/routes/pages.rs b/src/crates/monolith-server/src/routes/pages.rs
index 15f88dc..ca185ca 100644
--- a/src/crates/monolith-server/src/routes/pages.rs
+++ b/src/crates/monolith-server/src/routes/pages.rs
@@ -2837,7 +2837,15 @@ pub async fn translated_static_page(
// been refactored to read their copy from `t. We aim to meet WCAG 2.1 Level AA across every page we publish. That's the bar UK public-sector sites are held to; we hold ourselves to the same bar voluntarily. {{ (t.accessibility_para_commit | default("We aim to meet WCAG 2.1 Level AA across every page we publish. That's the bar UK public-sector sites are held to; we hold ourselves to the same bar voluntarily.")) | safe }} Specifically: {{ t.accessibility_para_specifically | default("Specifically:") }} Keyboard navigation Every interactive element is reachable by Tab. Focus rings are visible. A "Skip to content" link appears on Tab from every page. {{ t.accessibility_audit_keyboard_title | default("Keyboard navigation") }} {{ (t.accessibility_audit_keyboard_detail | default("Every interactive element is reachable by Tab. Focus rings are visible. A \"Skip to content\" link appears on Tab from every page.")) | safe }} Screen readers Semantic headings, labelled landmarks, accessible form fields, and ARIA roles where HTML semantics need a hand. {{ t.accessibility_audit_screenreaders_title | default("Screen readers") }} {{ t.accessibility_audit_screenreaders_detail | default("Semantic headings, labelled landmarks, accessible form fields, and ARIA roles where HTML semantics need a hand.") }} Reduced motion All animations respect {{ t.accessibility_audit_motion_title | default("Reduced motion") }} {{ (t.accessibility_audit_motion_detail | default("All animations respect Video and audio content Rare on this site, but when we embed third-party video (YouTube, etc.) we rely on the provider's captions, which aren't always available. When we produce our own media, we caption it. {{ t.accessibility_audit_video_title | default("Video and audio content") }} {{ t.accessibility_audit_video_detail | default("Rare on this site, but when we embed third-party video (YouTube, etc.) we rely on the provider's captions, which aren't always available. When we produce our own media, we caption it.") }} Automated translations Non-English pages are machine-translated. Phrasing can be awkward; factual meaning is preserved. English is the canonical version — use the UK flag in the dateline to switch back. {{ t.accessibility_audit_translations_title | default("Automated translations") }} {{ t.accessibility_audit_translations_detail | default("Non-English pages are machine-translated. Phrasing can be awkward; factual meaning is preserved. English is the canonical version — use the UK flag in the dateline to switch back.") }} If something on this site is blocking you from reading it, tell us and we'll fix it. The fastest route is accessibility@signaldaily.co.uk. Include the page URL and what you tried to do — screenshots welcome. {{ (t.accessibility_para_report | default("If something on this site is blocking you from reading it, tell us and we'll fix it. The fastest route is accessibility@signaldaily.co.uk. Include the page URL and what you tried to do — screenshots welcome.")) | safe }} We aim to respond within two working days and to fix confirmed blockers within two weeks. Complex issues get an interim workaround while we build a proper fix. {{ t.accessibility_para_response | default("We aim to respond within two working days and to fix confirmed blockers within two weeks. Complex issues get an interim workaround while we build a proper fix.") }} Last reviewed April 2026. We review this statement whenever we make a significant change to the site, or at least once a year. {{ t.accessibility_para_statement | default("Last reviewed April 2026. We review this statement whenever we make a significant change to the site, or at least once a year.") }} Something we should be writing about, ideally with receipts. Anonymity respected. {{ t.contact_lane_tips_desc | default("Something we should be writing about, ideally with receipts. Anonymity respected.") }} Something we got wrong. We publish every correction in public, so be specific. {{ t.contact_lane_corrections_desc | default("Something we got wrong. We publish every correction in public, so be specific.") }} Everything else. Hello. Hire us. Argue with us. We read it all. {{ t.contact_lane_general_desc | default("Everything else. Hello. Hire us. Argue with us. We read it all.") }} Prefer a form? Use this one. Goes to the same inbox as info@signaldaily.co.uk. {{ (t.contact_dispatch_intro | default("Prefer a form? Use this one. Goes to the same inbox as info@signaldaily.co.uk.")) | safe }} You'll get a reply from Daniel, usually within a day. Weekends and UK bank holidays might take longer. If you've sent a tip, you may not hear back until we've done the reporting; assume silence means "we're working on it". {{ t.contact_next_para | default("You'll get a reply from Daniel, usually within a day. Weekends and UK bank holidays might take longer. If you've sent a tip, you may not hear back until we've done the reporting; assume silence means \"we're working on it\".") }} Every cookie set by this site, in one place. Everything outside the "essential" row only runs with your consent. {{ t.cookies_para_ledger_intro | default("Every cookie set by this site, in one place. Everything outside the \"essential\" row only runs with your consent.") }}alt=\"\" when decorative).",
+ "accessibility_li_colour": "Colour is never the only way information is conveyed.",
+ "accessibility_li_motion": "The site respects prefers-reduced-motion and your browser's zoom settings.",
+ "accessibility_li_contrast": "Contrast meets or exceeds 4.5:1 for body text and 3:1 for large text.",
+ "accessibility_heading_today": "Where we are today",
+ "accessibility_audit_label_pass": "Conforms",
+ "accessibility_audit_label_partial": "Partially conforms",
+ "accessibility_audit_keyboard_title": "Keyboard navigation",
+ "accessibility_audit_keyboard_detail": "Every interactive element is reachable by Tab. Focus rings are visible. A \"Skip to content\" link appears on Tab from every page.",
+ "accessibility_audit_screenreaders_title": "Screen readers",
+ "accessibility_audit_screenreaders_detail": "Semantic headings, labelled landmarks, accessible form fields, and ARIA roles where HTML semantics need a hand.",
+ "accessibility_audit_motion_title": "Reduced motion",
+ "accessibility_audit_motion_detail": "All animations respect prefers-reduced-motion: reduce and collapse to instantaneous state changes.",
+ "accessibility_audit_video_title": "Video and audio content",
+ "accessibility_audit_video_detail": "Rare on this site, but when we embed third-party video (YouTube, etc.) we rely on the provider's captions, which aren't always available. When we produce our own media, we caption it.",
+ "accessibility_audit_translations_title": "Automated translations",
+ "accessibility_audit_translations_detail": "Non-English pages are machine-translated. Phrasing can be awkward; factual meaning is preserved. English is the canonical version — use the UK flag in the dateline to switch back.",
+ "accessibility_heading_report": "How to report an issue",
+ "accessibility_para_report": "If something on this site is blocking you from reading it, tell us and we'll fix it. The fastest route is accessibility@signaldaily.co.uk. Include the page URL and what you tried to do — screenshots welcome.",
+ "accessibility_para_response": "We aim to respond within two working days and to fix confirmed blockers within two weeks. Complex issues get an interim workaround while we build a proper fix.",
+ "accessibility_heading_statement": "This statement",
+ "accessibility_para_statement": "Last reviewed April 2026. We review this statement whenever we make a significant change to the site, or at least once a year.",
+
+ "contact_section_kicker": "EDITORIAL · CONTACT",
+ "contact_subtitle": "Reach the newsroom.",
+ "contact_title": "Get in touch.",
+ "contact_lead": "Pick the right channel and your message will actually be read. Generic PR pitches get a polite ignore; real tips and sharp questions get a real answer.",
+ "contact_meta": "Contact Signal Daily — tips, corrections, and general enquiries.",
+ "contact_lanes_heading": "Pick your lane",
+ "contact_lane_tips_label": "Tips",
+ "contact_lane_tips_desc": "Something we should be writing about, ideally with receipts. Anonymity respected.",
+ "contact_lane_corrections_label": "Corrections",
+ "contact_lane_corrections_desc": "Something we got wrong. We publish every correction in public, so be specific.",
+ "contact_lane_general_label": "General",
+ "contact_lane_general_desc": "Everything else. Hello. Hire us. Argue with us. We read it all.",
+ "contact_dispatch_heading": "Or send a dispatch",
+ "contact_dispatch_intro": "Prefer a form? Use this one. Goes to the same inbox as info@signaldaily.co.uk.",
+ "contact_form_name_label": "Your name",
+ "contact_form_email_label": "Reply-to email",
+ "contact_form_message_label": "Message",
+ "contact_form_submit": "Send dispatch →",
+ "contact_next_heading": "What happens next",
+ "contact_next_para": "You'll get a reply from Daniel, usually within a day. Weekends and UK bank holidays might take longer. If you've sent a tip, you may not hear back until we've done the reporting; assume silence means \"we're working on it\".",
+
+ "cookies_section_kicker": "POLICIES · COOKIES",
+ "cookies_subtitle": "Every cookie this site sets, what it does, how long it lives.",
+ "cookies_title": "Cookie policy.",
+ "cookies_lead": "Cookies are tiny text files the site stores in your browser. Some we need to make the site work. A few others, only with your consent. No tracking cookies. No ad cookies. No re-targeting. Here's the full ledger.",
+ "cookies_meta": "Cookie policy for Signal Daily — the complete list of cookies we set and their purpose.",
+ "cookies_heading_ledger": "The ledger",
+ "cookies_para_ledger_intro": "Every cookie set by this site, in one place. Everything outside the \"essential\" row only runs with your consent.",
+ "cookies_table_col_name": "Name",
+ "cookies_table_col_category": "Category",
+ "cookies_table_col_purpose": "Purpose",
+ "cookies_table_col_duration": "Duration",
+ "cookies_chip_essential": "Essential",
+ "cookies_chip_preferences": "Preferences",
+ "cookies_chip_analytics": "Analytics",
+ "cookies_duration_session": "Session",
+ "cookies_duration_1_year": "1 year",
+ "cookies_duration_2_years": "2 years",
+ "cookies_row_consent_purpose": "Remembers that you've set a preference so the banner doesn't show again.",
+ "cookies_row_session_purpose": "Authenticates your login session if you have an account. Signed out visitors never receive this.",
+ "cookies_row_csrf_purpose": "Protects forms (contact, newsletter, comments) from cross-site request forgery.",
+ "cookies_row_lang_purpose": "Remembers the language you chose from the flag switcher.",
+ "cookies_row_theme_purpose": "Remembers whether you picked light or dark mode.",
+ "cookies_row_ga_purpose": "Google Analytics, only set if you've opted in. Counts unique visits in an anonymised way.",
+ "cookies_manage_link": "Manage my preferences →",
+ "cookies_heading_third_party": "Third-party cookies",
+ "cookies_para_third_party": "Some embedded content (YouTube videos, Cloudflare Turnstile) may set cookies from those services. We don't control those; if the embed is loaded, their cookies apply. We only load a third-party embed after you interact with it or give explicit consent.",
+ "cookies_heading_control": "How to control cookies",
+ "cookies_para_control_lead": "Three ways, pick one:",
+ "cookies_control_site": "This site. Click the small cookie icon in the bottom-right corner of any page, or use the button above.",
+ "cookies_control_browser": "Your browser. Every major browser lets you block or delete cookies site-by-site or globally. Blocking essential cookies will break parts of the site.",
+ "cookies_control_private": "Private browsing. Opening the site in a private/incognito window means cookies are deleted when you close the window.",
+ "cookies_heading_block_essential": "If you block essential cookies",
+ "cookies_para_block_essential": "Login, comments, and the consent banner itself all stop working. The rest of the site still renders — you just won't be able to set preferences or interact.",
+ "cookies_heading_changes": "Changes",
+ "cookies_para_changes": "If we start using a new cookie, it goes in the ledger above and gets a category in the consent banner. Last reviewed April 2026.",
+
+ "corrections_section_kicker": "EDITORIAL · CORRECTIONS",
+ "corrections_subtitle": "We publish every correction in public.",
+ "corrections_title": "Corrections.",
+ "corrections_lead": "Everyone gets things wrong. Newsrooms differ in what they do next. When we make a factual mistake, we fix the piece, say what changed, and keep the record here. Typos don't count — we fix those quietly.",
+ "corrections_meta": "Corrections log — every factual error we've published and the fix we made.",
+ "corrections_heading_how": "How corrections work",
+ "corrections_para_intro": "If a piece says something factually wrong, we:",
+ "corrections_step_fix": "Fix the piece at its original URL.",
+ "corrections_step_note": "Add a note at the bottom of the piece explaining what changed.",
+ "corrections_step_log": "Add a one-line entry to this page, newest first.",
+ "corrections_para_policy": "We don't silently edit. We don't \"unpublish\" to hide a mistake. If the mistake is big enough that an edit can't repair it, we retract the piece and say why.",
+ "corrections_heading_log": "The log",
+ "corrections_empty": "No corrections to date. That isn't a brag — typos don't count, and the newsroom is new. Keep us honest: corrections@signaldaily.co.uk.",
+ "corrections_heading_flag": "Flagging something",
+ "corrections_para_flag": "Found a factual error in a published piece? Email corrections@signaldaily.co.uk with the URL and what's wrong. We read every message and reply to any that deserve one.",
+
+ "privacy_section_kicker": "POLICIES · PRIVACY",
+ "privacy_subtitle": "What we collect, why, and how long we keep it.",
+ "privacy_title": "Privacy policy.",
+ "privacy_lead": "Here's the short version: we collect as little data as we can get away with, we don't sell anything to anyone, and we won't pretend a cookie banner makes everything fine. What follows is the full list of what we do hold, why, and how to get your data out.",
+ "privacy_meta": "Privacy policy for Signal Daily — what we collect, why, and how long.",
+ "privacy_heading_summary": "What this page covers in 30 seconds",
+ "privacy_summary_controller": "We're the data controller for signaldaily.co.uk. That's Daniel Benson in Herefordshire.",
+ "privacy_summary_minimum": "We collect the minimum to run the site and the newsletter.",
+ "privacy_summary_no_sell": "We never sell, rent, or share your data for marketing.",
+ "privacy_summary_access": "You can ask to see, export, or delete what we have — details below.",
+ "privacy_summary_processors": "Our only processors are the services that run the site itself (hosting, email delivery, analytics).",
+ "privacy_heading_collect": "What we actually collect",
+ "privacy_table_what": "What",
+ "privacy_table_why": "Why",
+ "privacy_table_how_long": "How long",
+ "privacy_row_essential_what": "Essential cookies",
+ "privacy_row_essential_why": "Login sessions, CSRF protection, your cookie preference, your language choice. The site stops working without these.",
+ "privacy_row_essential_how_long": "Session or up to 1 year",
+ "privacy_row_analytics_what": "Analytics",
+ "privacy_row_analytics_why": "Aggregated page views so we know which pieces land. No fingerprinting, no third-party ad networks. Opt-in via the cookie banner.",
+ "privacy_row_analytics_how_long": "30 days",
+ "privacy_row_logs_what": "Server logs",
+ "privacy_row_logs_why": "Request logs with IP + user agent, for abuse detection and debugging. Never sold, never joined with other data.",
+ "privacy_row_logs_how_long": "14 days",
+ "privacy_row_contact_what": "Contact form submissions",
+ "privacy_row_contact_why": "Your name, email, and message, so we can reply. That's it.",
+ "privacy_row_contact_how_long": "Until the conversation ends, then deleted within 90 days",
+ "privacy_row_newsletter_what": "Newsletter sign-ups",
+ "privacy_row_newsletter_why": "Email address, subscribe date, and whether you've confirmed. For sending the newsletter and nothing else.",
+ "privacy_row_newsletter_how_long": "Until you unsubscribe",
+ "privacy_row_comments_what": "Comments (when enabled)",
+ "privacy_row_comments_why": "Your name, email, and comment text, so we can publish it under your name and moderate abuse.",
+ "privacy_row_comments_how_long": "As long as the comment is published",
+ "privacy_heading_rights": "Your rights",
+ "privacy_rights_intro": "Under UK GDPR you can do all of the following. We'll respond to any request within 30 days and usually within 48 hours.",
+ "privacy_rights_see": "See what we have on you. Email us and we'll send you every record tied to your email address.",
+ "privacy_rights_correct": "Correct anything wrong. Tell us what needs updating and we'll do it.",
+ "privacy_rights_delete": "Delete everything. We'll wipe your newsletter subscription, contact-form history, and comment history on request.",
+ "privacy_rights_object": "Object to a use. If you don't like how we're using a specific thing, tell us and we'll stop.",
+ "privacy_rights_export": "Export it. We'll send you a machine-readable copy of your data.",
+ "privacy_rights_exercise": "To exercise any of these, email privacy@signaldaily.co.uk.",
+ "privacy_heading_who_else": "Who else sees it",
+ "privacy_who_else_intro": "Three third parties, all processors bound by data-processing agreements:",
+ "privacy_who_else_hosting": "Hosting provider — serves the website and runs the database.",
+ "privacy_who_else_email": "Email delivery service — sends the newsletter and transactional emails. Sees your email address and the message.",
+ "privacy_who_else_analytics": "Analytics — counts visits when you've opted in. Sees an anonymised hit, not you personally.",
+ "privacy_who_else_no_ads": "No advertising networks. No \"data partners\". No affiliate networks receiving your address.",
+ "privacy_heading_transfers": "International transfers",
+ "privacy_transfers_para": "Our hosting is in the EU. Newsletter delivery may route through the US under standard contractual clauses. Analytics data, when collected, stays in the EU.",
+ "privacy_heading_children": "Children",
+ "privacy_children_para": "Signal Daily isn't directed at children under 13 and we don't knowingly collect data from anyone under 13. If you are a parent and believe we have, email privacy@signaldaily.co.uk and we'll delete it.",
+ "privacy_heading_cookies": "Cookies",
+ "privacy_cookies_para": "Full breakdown on the cookie policy page. You can manage your preferences any time by clicking the small cookie icon in the bottom-right corner of any page.",
+ "privacy_heading_complaints": "Complaints",
+ "privacy_complaints_para": "If you think we've mishandled your data, email us first — nine times out of ten we can fix it the same day. If you're still unhappy, you can complain to the UK Information Commissioner's Office at ico.org.uk/make-a-complaint.",
+ "privacy_heading_controller": "Data controller",
+ "privacy_controller_para": "Signal Daily · Daniel Benson · Herefordshire, United Kingdom · privacy@signaldaily.co.uk",
+ "privacy_heading_changes": "Changes to this policy",
+ "privacy_changes_para": "When we change anything on this page, we update the \"Last reviewed\" date below and, if the change is material, we email active newsletter subscribers before it takes effect. Last reviewed April 2026.",
+
+ "terms_section_kicker": "POLICIES · TERMS",
+ "terms_subtitle": "The agreement between this site and the person reading it.",
+ "terms_title": "Terms of use.",
+ "terms_lead": "Short and readable rather than long and impenetrable. By using signaldaily.co.uk you agree to these terms. If you don't, don't use the site — nothing here is compulsory.",
+ "terms_meta": "Terms of use for Signal Daily — plain-English rules that govern the site.",
+ "terms_toc_heading": "Contents",
+ "terms_toc_who_we_are": "Who we are",
+ "terms_toc_how_to_use": "How to use this site",
+ "terms_toc_what_we_publish": "What we publish",
+ "terms_toc_what_not_allowed": "What isn't allowed",
+ "terms_toc_if_it_breaks": "If something breaks",
+ "terms_toc_change_log": "Change log and law",
+ "terms_heading_who_we_are": "Who we are",
+ "terms_para_who_we_are": "Signal Daily is an independent newsroom run by Daniel Benson from Herefordshire, United Kingdom. It publishes at signaldaily.co.uk. These terms describe the agreement between Signal Daily (\"we\", \"us\") and anyone visiting the site (\"you\").",
+ "terms_heading_how_to_use": "How to use this site",
+ "terms_para_how_to_use_1": "Read anything you like. Share links — they're free. Quote us in articles or social posts with attribution. Print pieces for personal use. Recommend us to a friend. None of those need our permission.",
+ "terms_para_how_to_use_2": "What you do need permission for: republishing an entire article somewhere else, commercial use (training models, reprinting in a paid-for publication, redistributing programmatically), or scraping the site at volume. Ask first — we usually say yes for journalistic or academic reuse.",
+ "terms_heading_what_we_publish": "What we publish",
+ "terms_para_what_we_publish_1": "We publish opinions, reporting, and guides in the topics listed on the about page. We try hard to be accurate; when we fail, we say so on the corrections page.",
+ "terms_para_what_we_publish_2": "Opinions are labelled as opinions. Reporting is sourced. Guides are tested on an actual machine by an actual human. Everything here is written by people, even when that takes longer.",
+ "terms_para_what_we_publish_3": "Unless clearly stated otherwise, everything on the site — text, images, templates, and the underlying CMS — is copyright Signal Daily. The software that runs the site (Monolith CMS) has its own licence.",
+ "terms_heading_what_not_allowed": "What isn't allowed",
+ "terms_para_what_not_allowed_lead": "You agree not to:",
+ "terms_li_not_allowed_1": "Try to break into the site or any of its services.",
+ "terms_li_not_allowed_2": "Scrape content at volume without asking, or use automated tools to overwhelm the site.",
+ "terms_li_not_allowed_3": "Submit content (via comments, contact forms, anywhere) that is unlawful, harassing, hateful, or that infringes someone else's rights.",
+ "terms_li_not_allowed_4": "Use the site to run your own business without a written agreement — e.g. as a content farm, scrape source, or model-training corpus.",
+ "terms_para_what_not_allowed_enforcement": "We may remove any submission, block any account, and decline to serve any visitor who breaks these rules. In serious cases we'll report abuse to the relevant authorities.",
+ "terms_heading_if_it_breaks": "If something breaks",
+ "terms_para_if_it_breaks_lead": "We do our best to keep the site running and accurate, but we offer no warranty that it will be continuously available or error-free. To the maximum extent permitted by law:",
+ "terms_li_if_it_breaks_1": "We aren't liable for losses — direct, indirect, consequential — arising from your use of the site.",
+ "terms_li_if_it_breaks_2": "Nothing in these terms limits liability that can't legally be limited (death, personal injury, or fraud).",
+ "terms_li_if_it_breaks_3": "If a piece of our content turns out to be wrong and you act on it, that's on you. We correct quickly when we learn about errors, but the site is journalism, not professional advice.",
+ "terms_heading_change_log": "Change log and law",
+ "terms_para_change_log_1": "These terms are governed by the laws of England and Wales. Any dispute that can't be resolved by a polite email goes to the courts of England and Wales.",
+ "terms_para_change_log_2": "We may update these terms. When we make material changes we'll note it on this page. Continued use of the site after a change counts as acceptance. Last updated April 2026.",
+ "terms_para_change_log_questions": "Questions: info@signaldaily.co.uk."
}
diff --git a/themes/signaldaily/templates/page-accessibility.html b/themes/signaldaily/templates/page-accessibility.html
index bb629a0..8d5a825 100644
--- a/themes/signaldaily/templates/page-accessibility.html
+++ b/themes/signaldaily/templates/page-accessibility.html
@@ -1,78 +1,80 @@
-{# Example footer page from signaldaily.co.uk. Replace the hardcoded copy
- with your own, or delete this file to fall back to `page.html`. #}
+{# Bespoke accessibility page. Copy lives in `themes/signaldaily/i18n/en.json`
+ under the `accessibility_*` keys so translated paths can render the same
+ layout (np-broadsheet shell + custom np-audit component) with
+ auto-translated strings. #}
{% extends "partials/page-shell.html" %}
{% set page_kind = "accessibility" %}
-{% set page_section_kicker = "POLICIES · ACCESSIBILITY" %}
-{% set page_subtitle = "Our accessibility commitment, in plain English." %}
-{% set page_title = "Accessibility." %}
-{% set page_lead = "Signal Daily is built to be readable by everyone. That includes keyboard-only visitors, screen-reader users, people with reduced motion settings, and anyone who just likes a bigger font. Here's the state of play and what we're working on." %}
-{% set page_meta = "Accessibility statement for Signal Daily — our commitment, known gaps, and how to report an issue." %}
+{% set page_section_kicker = t.accessibility_section_kicker | default("POLICIES · ACCESSIBILITY") %}
+{% set page_subtitle = t.accessibility_subtitle | default("Our accessibility commitment, in plain English.") %}
+{% set page_title = t.accessibility_title | default("Accessibility.") %}
+{% set page_lead = t.accessibility_lead | default("Signal Daily is built to be readable by everyone. That includes keyboard-only visitors, screen-reader users, people with reduced motion settings, and anyone who just likes a bigger font. Here's the state of play and what we're working on.") %}
+{% set page_meta = t.accessibility_meta | default("Accessibility statement for Signal Daily — our commitment, known gaps, and how to report an issue.") %}
{% block page_body %}
-What we commit to
+{{ t.accessibility_heading_commit | default("What we commit to") }}
-
-
-alt="" when decorative).prefers-reduced-motion and your browser's zoom settings.alt=\"\" when decorative).")) | safe }}prefers-reduced-motion and your browser's zoom settings.")) | safe }}Where we are today
+{{ t.accessibility_heading_today | default("Where we are today") }}
-prefers-reduced-motion: reduce and collapse to instantaneous state changes.prefers-reduced-motion: reduce and collapse to instantaneous state changes.")) | safe }}How to report an issue
+{{ t.accessibility_heading_report | default("How to report an issue") }}
-This statement
+{{ t.accessibility_heading_statement | default("This statement") }}
-Pick your lane
+{{ t.contact_lanes_heading | default("Pick your lane") }}
Or send a dispatch
+{{ t.contact_dispatch_heading | default("Or send a dispatch") }}
-What happens next
+{{ t.contact_next_heading | default("What happens next") }}
-The ledger
+{{ t.cookies_heading_ledger | default("The ledger") }}
-
@@ -68,29 +68,29 @@
-
Name
- Category
- Purpose
- Duration
+ {{ t.cookies_table_col_name | default("Name") }}
+ {{ t.cookies_table_col_category | default("Category") }}
+ {{ t.cookies_table_col_purpose | default("Purpose") }}
+ {{ t.cookies_table_col_duration | default("Duration") }}
cookie_consent
-
- Remembers that you've set a preference so the banner doesn't show again.
- 1 year
+
+ {{ t.cookies_row_consent_purpose | default("Remembers that you've set a preference so the banner doesn't show again.") }}
+ {{ t.cookies_duration_1_year | default("1 year") }}
session_id
-
- Authenticates your login session if you have an account. Signed out visitors never receive this.
- Session
+
+ {{ t.cookies_row_session_purpose | default("Authenticates your login session if you have an account. Signed out visitors never receive this.") }}
+ {{ t.cookies_duration_session | default("Session") }}
csrf_token
-
- Protects forms (contact, newsletter, comments) from cross-site request forgery.
- Session
+
+ {{ t.cookies_row_csrf_purpose | default("Protects forms (contact, newsletter, comments) from cross-site request forgery.") }}
+ {{ t.cookies_duration_session | default("Session") }}
lang_pref
-
- Remembers the language you chose from the flag switcher.
- 1 year
+
+ {{ t.cookies_row_lang_purpose | default("Remembers the language you chose from the flag switcher.") }}
+ {{ t.cookies_duration_1_year | default("1 year") }}
theme_pref
-
- Remembers whether you picked light or dark mode.
- 1 year
+
+ {{ t.cookies_row_theme_purpose | default("Remembers whether you picked light or dark mode.") }}
+ {{ t.cookies_duration_1_year | default("1 year") }}
_ga, _ga_*
-
- Google Analytics, only set if you've opted in. Counts unique visits in an anonymised way.
- 2 years
+
+ {{ t.cookies_row_ga_purpose | default("Google Analytics, only set if you've opted in. Counts unique visits in an anonymised way.") }}
+ {{ t.cookies_duration_2_years | default("2 years") }}
The ledger
{# Jump-link to the floating cookie-consent FAB at the bottom-right of every
page; clicking the FAB opens the preferences panel. No inline JS so the
strict `script-src 'self'
Some embedded content (YouTube videos, Cloudflare Turnstile) may set cookies from those services. We don't control those; if the embed is loaded, their cookies apply. We only load a third-party embed after you interact with it or give explicit consent.
+{{ t.cookies_para_third_party | default("Some embedded content (YouTube videos, Cloudflare Turnstile) may set cookies from those services. We don't control those; if the embed is loaded, their cookies apply. We only load a third-party embed after you interact with it or give explicit consent.") }}
-Three ways, pick one:
+{{ t.cookies_para_control_lead | default("Three ways, pick one:") }}
Login, comments, and the consent banner itself all stop working. The rest of the site still renders — you just won't be able to set preferences or interact.
+{{ t.cookies_para_block_essential | default("Login, comments, and the consent banner itself all stop working. The rest of the site still renders — you just won't be able to set preferences or interact.") }}
-If we start using a new cookie, it goes in the ledger above and gets a category in the consent banner. Last reviewed April 2026.
+{{ t.cookies_para_changes | default("If we start using a new cookie, it goes in the ledger above and gets a category in the consent banner. Last reviewed April 2026.") }}
{% endblock %} diff --git a/themes/signaldaily/templates/page-corrections.html b/themes/signaldaily/templates/page-corrections.html index 05a2d53..2ee5e25 100644 --- a/themes/signaldaily/templates/page-corrections.html +++ b/themes/signaldaily/templates/page-corrections.html @@ -3,11 +3,11 @@ {% extends "partials/page-shell.html" %} {% set page_kind = "corrections" %} -{% set page_section_kicker = "EDITORIAL · CORRECTIONS" %} -{% set page_subtitle = "We publish every correction in public." %} -{% set page_title = "Corrections." %} -{% set page_lead = "Everyone gets things wrong. Newsrooms differ in what they do next. When we make a factual mistake, we fix the piece, say what changed, and keep the record here. Typos don't count — we fix those quietly." %} -{% set page_meta = "Corrections log — every factual error we've published and the fix we made." %} +{% set page_section_kicker = t.corrections_section_kicker | default("EDITORIAL · CORRECTIONS") %} +{% set page_subtitle = t.corrections_subtitle | default("We publish every correction in public.") %} +{% set page_title = t.corrections_title | default("Corrections.") %} +{% set page_lead = t.corrections_lead | default("Everyone gets things wrong. Newsrooms differ in what they do next. When we make a factual mistake, we fix the piece, say what changed, and keep the record here. Typos don't count — we fix those quietly.") %} +{% set page_meta = t.corrections_meta | default("Corrections log — every factual error we've published and the fix we made.") %} {# v1 corrections log — hand-maintained. A future CMS table can replace this. TODO(v2): when `entries` becomes user-sourced, whitelist `e.category` against @@ -17,19 +17,19 @@ {% block page_body %} -If a piece says something factually wrong, we:
+{{ t.corrections_para_intro | default("If a piece says something factually wrong, we:") }}
We don't silently edit. We don't "unpublish" to hide a mistake. If the mistake is big enough that an edit can't repair it, we retract the piece and say why.
+{{ t.corrections_para_policy | default("We don't silently edit. We don't \"unpublish\" to hide a mistake. If the mistake is big enough that an edit can't repair it, we retract the piece and say why.") }}
-Found a factual error in a published piece? Email corrections@signaldaily.co.uk with the URL and what's wrong. We read every message and reply to any that deserve one.
+{{ (t.corrections_para_flag | default("Found a factual error in a published piece? Email corrections@signaldaily.co.uk with the URL and what's wrong. We read every message and reply to any that deserve one.")) | safe }}
{% endblock %} diff --git a/themes/signaldaily/templates/page-privacy.html b/themes/signaldaily/templates/page-privacy.html index 67af859..63c9f4c 100644 --- a/themes/signaldaily/templates/page-privacy.html +++ b/themes/signaldaily/templates/page-privacy.html @@ -1,118 +1,120 @@ -{# Example footer page from signaldaily.co.uk. Replace the hardcoded copy - with your own, or delete this file to fall back to `page.html`. #} +{# Bespoke privacy page. Copy lives in `themes/signaldaily/i18n/en.json` + under the `privacy_*` keys so translated paths can render the same + layout (np-broadsheet shell + custom np-data-inventory / np-rights-list + components) with auto-translated strings. #} {% extends "partials/page-shell.html" %} {% set page_kind = "privacy" %} -{% set page_section_kicker = "POLICIES · PRIVACY" %} -{% set page_subtitle = "What we collect, why, and how long we keep it." %} -{% set page_title = "Privacy policy." %} -{% set page_lead = "Here's the short version: we collect as little data as we can get away with, we don't sell anything to anyone, and we won't pretend a cookie banner makes everything fine. What follows is the full list of what we do hold, why, and how to get your data out." %} -{% set page_meta = "Privacy policy for Signal Daily — what we collect, why, and how long." %} +{% set page_section_kicker = t.privacy_section_kicker | default("POLICIES · PRIVACY") %} +{% set page_subtitle = t.privacy_subtitle | default("What we collect, why, and how long we keep it.") %} +{% set page_title = t.privacy_title | default("Privacy policy.") %} +{% set page_lead = t.privacy_lead | default("Here's the short version: we collect as little data as we can get away with, we don't sell anything to anyone, and we won't pretend a cookie banner makes everything fine. What follows is the full list of what we do hold, why, and how to get your data out.") %} +{% set page_meta = t.privacy_meta | default("Privacy policy for Signal Daily — what we collect, why, and how long.") %} {% block page_body %} -| What | -Why | -How long | +{{ t.privacy_table_what | default("What") }} | +{{ t.privacy_table_why | default("Why") }} | +{{ t.privacy_table_how_long | default("How long") }} |
|---|---|---|---|---|---|
| Essential cookies | -Login sessions, CSRF protection, your cookie preference, your language choice. The site stops working without these. | -Session or up to 1 year | +{{ t.privacy_row_essential_what | default("Essential cookies") }} | +{{ t.privacy_row_essential_why | default("Login sessions, CSRF protection, your cookie preference, your language choice. The site stops working without these.") }} | +{{ t.privacy_row_essential_how_long | default("Session or up to 1 year") }} |
| Analytics | -Aggregated page views so we know which pieces land. No fingerprinting, no third-party ad networks. Opt-in via the cookie banner. | -30 days | +{{ t.privacy_row_analytics_what | default("Analytics") }} | +{{ t.privacy_row_analytics_why | default("Aggregated page views so we know which pieces land. No fingerprinting, no third-party ad networks. Opt-in via the cookie banner.") }} | +{{ t.privacy_row_analytics_how_long | default("30 days") }} |
| Server logs | -Request logs with IP + user agent, for abuse detection and debugging. Never sold, never joined with other data. | -14 days | +{{ t.privacy_row_logs_what | default("Server logs") }} | +{{ t.privacy_row_logs_why | default("Request logs with IP + user agent, for abuse detection and debugging. Never sold, never joined with other data.") }} | +{{ t.privacy_row_logs_how_long | default("14 days") }} |
| Contact form submissions | -Your name, email, and message, so we can reply. That's it. | -Until the conversation ends, then deleted within 90 days | +{{ t.privacy_row_contact_what | default("Contact form submissions") }} | +{{ t.privacy_row_contact_why | default("Your name, email, and message, so we can reply. That's it.") }} | +{{ t.privacy_row_contact_how_long | default("Until the conversation ends, then deleted within 90 days") }} |
| Newsletter sign-ups | -Email address, subscribe date, and whether you've confirmed. For sending the newsletter and nothing else. | -Until you unsubscribe | +{{ t.privacy_row_newsletter_what | default("Newsletter sign-ups") }} | +{{ t.privacy_row_newsletter_why | default("Email address, subscribe date, and whether you've confirmed. For sending the newsletter and nothing else.") }} | +{{ t.privacy_row_newsletter_how_long | default("Until you unsubscribe") }} |
| Comments (when enabled) | -Your name, email, and comment text, so we can publish it under your name and moderate abuse. | -As long as the comment is published | +{{ t.privacy_row_comments_what | default("Comments (when enabled)") }} | +{{ t.privacy_row_comments_why | default("Your name, email, and comment text, so we can publish it under your name and moderate abuse.") }} | +{{ t.privacy_row_comments_how_long | default("As long as the comment is published") }} |
Under UK GDPR you can do all of the following. We'll respond to any request within 30 days and usually within 48 hours.
+{{ t.privacy_rights_intro | default("Under UK GDPR you can do all of the following. We'll respond to any request within 30 days and usually within 48 hours.") }}
To exercise any of these, email privacy@signaldaily.co.uk.
+{{ (t.privacy_rights_exercise | default("To exercise any of these, email privacy@signaldaily.co.uk.")) | safe }}
-Three third parties, all processors bound by data-processing agreements:
+{{ t.privacy_who_else_intro | default("Three third parties, all processors bound by data-processing agreements:") }}
No advertising networks. No "data partners". No affiliate networks receiving your address.
+{{ t.privacy_who_else_no_ads | default("No advertising networks. No \"data partners\". No affiliate networks receiving your address.") }}
-Our hosting is in the EU. Newsletter delivery may route through the US under standard contractual clauses. Analytics data, when collected, stays in the EU.
+{{ t.privacy_transfers_para | default("Our hosting is in the EU. Newsletter delivery may route through the US under standard contractual clauses. Analytics data, when collected, stays in the EU.") }}
-Signal Daily isn't directed at children under 13 and we don't knowingly collect data from anyone under 13. If you are a parent and believe we have, email privacy@signaldaily.co.uk and we'll delete it.
+{{ (t.privacy_children_para | default("Signal Daily isn't directed at children under 13 and we don't knowingly collect data from anyone under 13. If you are a parent and believe we have, email privacy@signaldaily.co.uk and we'll delete it.")) | safe }}
-Full breakdown on the cookie policy page. You can manage your preferences any time by clicking the small cookie icon in the bottom-right corner of any page.
+{{ (t.privacy_cookies_para | default("Full breakdown on the cookie policy page. You can manage your preferences any time by clicking the small cookie icon in the bottom-right corner of any page.")) | replace("{lang_prefix}", lang_prefix) | safe }}
-If you think we've mishandled your data, email us first — nine times out of ten we can fix it the same day. If you're still unhappy, you can complain to the UK Information Commissioner's Office at ico.org.uk/make-a-complaint.
+{{ (t.privacy_complaints_para | default("If you think we've mishandled your data, email us first — nine times out of ten we can fix it the same day. If you're still unhappy, you can complain to the UK Information Commissioner's Office at ico.org.uk/make-a-complaint.")) | safe }}
-Signal Daily · Daniel Benson · Herefordshire, United Kingdom · privacy@signaldaily.co.uk
+{{ (t.privacy_controller_para | default("Signal Daily · Daniel Benson · Herefordshire, United Kingdom · privacy@signaldaily.co.uk")) | safe }}
-When we change anything on this page, we update the "Last reviewed" date below and, if the change is material, we email active newsletter subscribers before it takes effect. Last reviewed April 2026.
+{{ t.privacy_changes_para | default("When we change anything on this page, we update the \"Last reviewed\" date below and, if the change is material, we email active newsletter subscribers before it takes effect. Last reviewed April 2026.") }}
{% endblock %} diff --git a/themes/signaldaily/templates/page-terms.html b/themes/signaldaily/templates/page-terms.html index d8f03b9..57c0c3b 100644 --- a/themes/signaldaily/templates/page-terms.html +++ b/themes/signaldaily/templates/page-terms.html @@ -3,64 +3,64 @@ {% extends "partials/page-shell.html" %} {% set page_kind = "terms" %} -{% set page_section_kicker = "POLICIES · TERMS" %} -{% set page_subtitle = "The agreement between this site and the person reading it." %} -{% set page_title = "Terms of use." %} -{% set page_lead = "Short and readable rather than long and impenetrable. By using signaldaily.co.uk you agree to these terms. If you don't, don't use the site — nothing here is compulsory." %} -{% set page_meta = "Terms of use for Signal Daily — plain-English rules that govern the site." %} +{% set page_section_kicker = t.terms_section_kicker | default("POLICIES · TERMS") %} +{% set page_subtitle = t.terms_subtitle | default("The agreement between this site and the person reading it.") %} +{% set page_title = t.terms_title | default("Terms of use.") %} +{% set page_lead = t.terms_lead | default("Short and readable rather than long and impenetrable. By using signaldaily.co.uk you agree to these terms. If you don't, don't use the site — nothing here is compulsory.") %} +{% set page_meta = t.terms_meta | default("Terms of use for Signal Daily — plain-English rules that govern the site.") %} {% block page_body %}Signal Daily is an independent newsroom run by Daniel Benson from Herefordshire, United Kingdom. It publishes at signaldaily.co.uk. These terms describe the agreement between Signal Daily ("we", "us") and anyone visiting the site ("you").
+{{ t.terms_para_who_we_are | default("Signal Daily is an independent newsroom run by Daniel Benson from Herefordshire, United Kingdom. It publishes at signaldaily.co.uk. These terms describe the agreement between Signal Daily (\"we\", \"us\") and anyone visiting the site (\"you\").") }}
-Read anything you like. Share links — they're free. Quote us in articles or social posts with attribution. Print pieces for personal use. Recommend us to a friend. None of those need our permission.
-What you do need permission for: republishing an entire article somewhere else, commercial use (training models, reprinting in a paid-for publication, redistributing programmatically), or scraping the site at volume. Ask first — we usually say yes for journalistic or academic reuse.
+{{ t.terms_para_how_to_use_1 | default("Read anything you like. Share links — they're free. Quote us in articles or social posts with attribution. Print pieces for personal use. Recommend us to a friend. None of those need our permission.") }}
+{{ t.terms_para_how_to_use_2 | default("What you do need permission for: republishing an entire article somewhere else, commercial use (training models, reprinting in a paid-for publication, redistributing programmatically), or scraping the site at volume. Ask first — we usually say yes for journalistic or academic reuse.") }}
-We publish opinions, reporting, and guides in the topics listed on the about page. We try hard to be accurate; when we fail, we say so on the corrections page.
-Opinions are labelled as opinions. Reporting is sourced. Guides are tested on an actual machine by an actual human. Everything here is written by people, even when that takes longer.
-Unless clearly stated otherwise, everything on the site — text, images, templates, and the underlying CMS — is copyright Signal Daily. The software that runs the site (Monolith CMS) has its own licence.
+{{ (t.terms_para_what_we_publish_1 | default("We publish opinions, reporting, and guides in the topics listed on the about page. We try hard to be accurate; when we fail, we say so on the corrections page.")) | replace("{lang_prefix}", lang_prefix) | safe }}
+{{ t.terms_para_what_we_publish_2 | default("Opinions are labelled as opinions. Reporting is sourced. Guides are tested on an actual machine by an actual human. Everything here is written by people, even when that takes longer.") }}
+{{ t.terms_para_what_we_publish_3 | default("Unless clearly stated otherwise, everything on the site — text, images, templates, and the underlying CMS — is copyright Signal Daily. The software that runs the site (Monolith CMS) has its own licence.") }}
-You agree not to:
+{{ t.terms_para_what_not_allowed_lead | default("You agree not to:") }}
We may remove any submission, block any account, and decline to serve any visitor who breaks these rules. In serious cases we'll report abuse to the relevant authorities.
+{{ t.terms_para_what_not_allowed_enforcement | default("We may remove any submission, block any account, and decline to serve any visitor who breaks these rules. In serious cases we'll report abuse to the relevant authorities.") }}
-We do our best to keep the site running and accurate, but we offer no warranty that it will be continuously available or error-free. To the maximum extent permitted by law:
+{{ t.terms_para_if_it_breaks_lead | default("We do our best to keep the site running and accurate, but we offer no warranty that it will be continuously available or error-free. To the maximum extent permitted by law:") }}
These terms are governed by the laws of England and Wales. Any dispute that can't be resolved by a polite email goes to the courts of England and Wales.
-We may update these terms. When we make material changes we'll note it on this page. Continued use of the site after a change counts as acceptance. Last updated April 2026.
-Questions: info@signaldaily.co.uk.
+{{ t.terms_para_change_log_1 | default("These terms are governed by the laws of England and Wales. Any dispute that can't be resolved by a polite email goes to the courts of England and Wales.") }}
+{{ t.terms_para_change_log_2 | default("We may update these terms. When we make material changes we'll note it on this page. Continued use of the site after a change counts as acceptance. Last updated April 2026.") }}
+{{ (t.terms_para_change_log_questions | default("Questions: info@signaldaily.co.uk.")) | safe }}