diff --git a/djangoproject/scss/_style.scss b/djangoproject/scss/_style.scss
index 3a6eb69d02..e958292c2c 100644
--- a/djangoproject/scss/_style.scss
+++ b/djangoproject/scss/_style.scss
@@ -3318,6 +3318,20 @@ hr {
}
}
+/* Improve accessibility for footnote links in tables */
+table sup a,
+.django-supported-versions sup a,
+.django-unsupported-versions sup a {
+ color: var(--link-color);
+ text-decoration: underline;
+
+ &:hover,
+ &:focus {
+ color: var(--primary-accent);
+ text-decoration: underline;
+ }
+}
+
form .footnote {
margin-top: 10px;
text-align: left;
diff --git a/djangoproject/settings/common.py b/djangoproject/settings/common.py
index fff6e1dfee..d9bd12c31d 100644
--- a/djangoproject/settings/common.py
+++ b/djangoproject/settings/common.py
@@ -57,6 +57,7 @@
FIXTURE_DIRS = [str(PROJECT_PACKAGE.joinpath("fixtures"))]
INSTALLED_APPS = [
+ "djangoproject", # Add main project app for template tags
"accounts",
"aggregator",
"blog",
diff --git a/djangoproject/templates/base_lite.html b/djangoproject/templates/base_lite.html
new file mode 100644
index 0000000000..e902a0d8ee
--- /dev/null
+++ b/djangoproject/templates/base_lite.html
@@ -0,0 +1,97 @@
+{% load static %}
+
+
+
+
+
+
+
+
+
+
+
+ {% block link_rel_tags %}{% endblock link_rel_tags %}
+
+
+
+
+
+
+
+
+
+ {% block og_tags %}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {% endblock og_tags %}
+
+ {% block title %}Django{% endblock %}
+
+ {% comment %}
+ Custom stylesheets block - allows for completely different styling
+ By default, no stylesheets are included to allow for custom styling
+ {% endcomment %}
+ {% block stylesheets %}
+ {% comment %}
+ Example usage:
+ {% block stylesheets %}
+
+
+ {% endblock %}
+ {% endcomment %}
+ {% endblock stylesheets %}
+
+ {% block head_extra %}{% endblock head_extra %}
+
+
+
+ {% comment %}
+ Skip link for accessibility - can be overridden if needed
+ {% endcomment %}
+ {% block skip_link %}
+ Skip to main content
+ {% endblock skip_link %}
+
+ {% comment %}
+ Optional minimal header - can be completely overridden or omitted
+ {% endcomment %}
+ {% block header %}{% endblock header %}
+
+ {% comment %}
+ Main content area - completely flexible
+ {% endcomment %}
+
+ {% block content %}{% endblock content %}
+
+
+ {% comment %}
+ Optional footer - can be completely overridden or omitted
+ {% endcomment %}
+ {% block footer %}{% endblock footer %}
+
+ {% comment %}
+ Minimal JavaScript block - only includes essentials
+ Can be overridden for custom JS needs
+ {% endcomment %}
+ {% block javascript %}
+ {% comment %}
+ Add any essential JavaScript here or override completely
+ {% endcomment %}
+ {% endblock javascript %}
+
+ {% block body_extra %}{% endblock body_extra %}
+
+
diff --git a/djangoproject/templates/flatpages/lite.html b/djangoproject/templates/flatpages/lite.html
new file mode 100644
index 0000000000..a434b91d05
--- /dev/null
+++ b/djangoproject/templates/flatpages/lite.html
@@ -0,0 +1,71 @@
+{% extends "base_lite.html" %}
+{% load static lite_filters %}
+
+{% comment %}
+Lite flatpage template for documents with custom styling
+
+This template is designed for one-off documents like annual reports,
+special publications, or any content that needs completely different
+styling from the main Django website.
+
+Usage:
+1. Create your flatpage in Django admin
+2. Set the template name to "flatpages/lite.html"
+3. Add custom CSS by creating blocks in your content or
+ by extending this template further
+
+Example custom styling approaches:
+
+Approach 1: Inline styles in flatpage content
+
+
+Approach 2: External stylesheet in flatpage content
+
+
+Approach 3: Create a custom template that extends this one
+{% extends "flatpages/lite.html" %}
+{% block stylesheets %}
+
+{% endblock %}
+{% endcomment %}
+
+{% block title %}{{ flatpage.title }}{% endblock %}
+{% block og_title %}{{ flatpage.title }}{% endblock %}
+
+{% comment %}
+Extract CSS and JS from flatpage content if present
+This allows content editors to include custom styles directly in the content
+{% endcomment %}
+{% block stylesheets %}
+ {% comment %}
+ Extract any or "
+
+ # Find all matches
+ links = re.findall(link_pattern, value, re.IGNORECASE | re.DOTALL)
+ styles = re.findall(style_pattern, value, re.IGNORECASE | re.DOTALL)
+
+ # Combine and return
+ head_content = "\n".join(links + styles)
+ return mark_safe(head_content)
+
+
+@register.filter
+def remove_head_tags(value):
+ """
+ Remove and ", "", value, flags=re.IGNORECASE | re.DOTALL
+ )
+
+ return mark_safe(value)
+
+
+@register.filter
+def extract_script_tags(value):
+ """
+ Extract "
+
+ # Find all matches
+ scripts = re.findall(script_pattern, value, re.IGNORECASE | re.DOTALL)
+
+ return mark_safe("\n".join(scripts))
+
+
+@register.filter
+def remove_script_tags(value):
+ """
+ Remove ", "", value, flags=re.IGNORECASE | re.DOTALL
+ )
+
+ return mark_safe(value)
+
+
+@register.filter
+def clean_content_for_lite(value):
+ """
+ Combined filter to clean flatpage content for lite templates
+ Removes both head tags and script tags
+
+ Usage: {{ flatpage.content|clean_content_for_lite }}
+ """
+ if not value:
+ return ""
+
+ # Remove head tags first, then script tags
+ value = remove_head_tags(value)
+ value = remove_script_tags(value)
+
+ return value