diff --git a/.github/workflows/site-validation.yml b/.github/workflows/site-validation.yml
index 505bc52..e189c83 100644
--- a/.github/workflows/site-validation.yml
+++ b/.github/workflows/site-validation.yml
@@ -66,6 +66,7 @@ jobs:
run: |
python scripts/check_site_navigation.py _site --site-url "$SITE_URL"
python scripts/check_site_links.py _site --site-url "$SITE_URL"
+ python scripts/check_site_branding.py _site
- uses: actions/upload-artifact@v4
with:
name: site-navigation-preview-${{ matrix.name }}
diff --git a/FMA/index.md b/FMA/index.md
index d6d3e3b..a684aef 100644
--- a/FMA/index.md
+++ b/FMA/index.md
@@ -17,7 +17,7 @@ alternate_zh: /zh-cn/FMA/
简中
-
+ {% include brand-logo.html %}
@@ -158,8 +158,4 @@ FMA is built around engineering mathematics and explicit data-processing rules:
> **FMA: mathematics, engineering and real markets — without magic promises.**
-
+{% include site-footer.html %}
diff --git a/FMA/instruments.md b/FMA/instruments.md
index 48e76b5..c386262 100644
--- a/FMA/instruments.md
+++ b/FMA/instruments.md
@@ -17,7 +17,7 @@ alternate_zh: /zh-cn/FMA/instruments.html
简中
-
+ {% include brand-logo.html %}
@@ -94,8 +94,4 @@ MDMG, LIFE, GECO, OZPH, ABIO, PRMD, GEMC.
| PLDRUB_TOM | rub | Palladium |
-
+{% include site-footer.html %}
diff --git a/FuzzyRoutines/index.md b/FuzzyRoutines/index.md
index a6b23fe..58368f5 100644
--- a/FuzzyRoutines/index.md
+++ b/FuzzyRoutines/index.md
@@ -19,7 +19,7 @@ alternate_zh: /zh-cn/FuzzyRoutines/
简中
-
+ {% include brand-logo.html %}
@@ -100,8 +100,4 @@ The project deliberately keeps its numerical objects readable: functions expose
- [Tests](https://github.com/Fuzzy-Technologies/FuzzyRoutines/tree/master/tests)
- [Apache-2.0 License](https://github.com/Fuzzy-Technologies/FuzzyRoutines/blob/master/LICENSE)
-
+{% include site-footer.html %}
diff --git a/TKSBrokerAPI/en/index.md b/TKSBrokerAPI/en/index.md
index aeb0c4a..9ef2066 100644
--- a/TKSBrokerAPI/en/index.md
+++ b/TKSBrokerAPI/en/index.md
@@ -15,7 +15,7 @@ alternate_ru: /TKSBrokerAPI/
RU
-
+ {% include brand-logo.html %}
@@ -157,8 +157,4 @@ if __name__ == "__main__":
More examples are available in the [project README](https://github.com/Fuzzy-Technologies/TKSBrokerAPI).
-
+{% include site-footer.html %}
diff --git a/TKSBrokerAPI/index.md b/TKSBrokerAPI/index.md
index 8624f14..e73b03c 100644
--- a/TKSBrokerAPI/index.md
+++ b/TKSBrokerAPI/index.md
@@ -15,7 +15,7 @@ description: Платформа ⚙️ TKSBrokerAPI для упрощённой
RU
-
+ {% include brand-logo.html %}
@@ -293,8 +293,4 @@ if __name__ == "__main__":
-
+{% include site-footer.html %}
diff --git a/_includes/brand-logo.html b/_includes/brand-logo.html
new file mode 100644
index 0000000..25a0a13
--- /dev/null
+++ b/_includes/brand-logo.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/_includes/brand-name.html b/_includes/brand-name.html
new file mode 100644
index 0000000..e36df3a
--- /dev/null
+++ b/_includes/brand-name.html
@@ -0,0 +1 @@
+Fuzzy Technologies®
\ No newline at end of file
diff --git a/_includes/site-footer.html b/_includes/site-footer.html
new file mode 100644
index 0000000..c20a3d7
--- /dev/null
+++ b/_includes/site-footer.html
@@ -0,0 +1,17 @@
+{% assign brand_lang = page.lang | default: "en" %}
+{% case brand_lang %}
+ {% when "ru" %}
+ {% assign certificate_hint = "Товарный знак № 1276641 — свидетельство Роспатента" %}
+ {% assign brand_motto = "Технологии · Знания · Наука" %}
+ {% when "zh-CN" %}
+ {% assign certificate_hint = "第 1276641 号商标 — 注册证书(俄罗斯 FIPS/Rospatent 网站)" %}
+ {% assign brand_motto = "技术 · 知识 · 科学" %}
+ {% else %}
+ {% assign certificate_hint = "Trademark No. 1276641 — registration certificate (Russian FIPS/Rospatent website)" %}
+ {% assign brand_motto = "Technologies · Knowledge · Science" %}
+{% endcase %}
+
diff --git a/_layouts/article.html b/_layouts/article.html
index affc10c..c747b7a 100644
--- a/_layouts/article.html
+++ b/_layouts/article.html
@@ -17,7 +17,7 @@
{% endif %}
@@ -141,14 +141,4 @@ {{ page.title }}
{{ articles_label }}
-
+{% include site-footer.html %}
diff --git a/_layouts/articles.html b/_layouts/articles.html
index 3e21af7..58f020d 100644
--- a/_layouts/articles.html
+++ b/_layouts/articles.html
@@ -29,7 +29,7 @@
{% endif %}
@@ -92,14 +92,4 @@
{% endfor %}
-
+{% include site-footer.html %}
diff --git a/index.md b/index.md
index edcea2f..3fa8f34 100644
--- a/index.md
+++ b/index.md
@@ -10,7 +10,7 @@ alternate_zh: /zh-cn/
---
@@ -135,8 +135,4 @@ alternate_zh: /zh-cn/
-
+{% include site-footer.html %}
diff --git a/ru/FMA/index.md b/ru/FMA/index.md
index 3e75aff..be29dbc 100644
--- a/ru/FMA/index.md
+++ b/ru/FMA/index.md
@@ -17,7 +17,7 @@ description: Сервисы биржевых сигналов Fuzzy Market Analy
简中
-
+ {% include brand-logo.html %}
@@ -205,8 +205,4 @@ FMA помогает принимать обоснованные решения,
*[Через тернии к звёздам: история создания торгового алгоритма](https://teletype.in/@tgilmullin/trading-algorithm-history)*
-
+{% include site-footer.html %}
diff --git a/ru/FMA/instruments.md b/ru/FMA/instruments.md
index 7784d76..0b2b556 100644
--- a/ru/FMA/instruments.md
+++ b/ru/FMA/instruments.md
@@ -17,7 +17,7 @@ description: Сервисы биржевых сигналов Fuzzy Market Analy
简中
-
+ {% include brand-logo.html %}
@@ -294,8 +294,4 @@ description: Сервисы биржевых сигналов Fuzzy Market Analy
| PLTRUB_TOM | rub | Платина. |
| PLDRUB_TOM | rub | Палладий. |
-
+{% include site-footer.html %}
diff --git a/ru/FuzzyRoutines/index.md b/ru/FuzzyRoutines/index.md
index 0e508b5..f257d2f 100644
--- a/ru/FuzzyRoutines/index.md
+++ b/ru/FuzzyRoutines/index.md
@@ -19,7 +19,7 @@ alternate_zh: /zh-cn/FuzzyRoutines/
简中
-
+ {% include brand-logo.html %}
@@ -100,8 +100,4 @@ FuzzyRoutines распространяется под лицензией Apache-
- [Тесты](https://github.com/Fuzzy-Technologies/FuzzyRoutines/tree/master/tests)
- [Лицензия Apache-2.0](https://github.com/Fuzzy-Technologies/FuzzyRoutines/blob/master/LICENSE)
-
+{% include site-footer.html %}
diff --git a/ru/index.md b/ru/index.md
index 858d703..4572040 100644
--- a/ru/index.md
+++ b/ru/index.md
@@ -10,7 +10,7 @@ alternate_zh: /zh-cn/
---
@@ -135,8 +135,4 @@ alternate_zh: /zh-cn/
-
+{% include site-footer.html %}
diff --git a/scripts/check_site_branding.py b/scripts/check_site_branding.py
new file mode 100644
index 0000000..8b060db
--- /dev/null
+++ b/scripts/check_site_branding.py
@@ -0,0 +1,143 @@
+"""Validate registered company branding on every rendered site page."""
+
+import argparse
+from html.parser import HTMLParser
+from pathlib import Path
+
+CERTIFICATE_URL = "https://fips.ru/EGD/e3ee2ab0-72e9-4524-a4b9-7123356f06fe"
+LOGO_URL = "/static/images/FuzzyTechnologies-Logo-registered.svg"
+HINTS = {
+ "en": "Trademark No. 1276641 — registration certificate (Russian FIPS/Rospatent website)",
+ "ru": "Товарный знак № 1276641 — свидетельство Роспатента",
+ "zh-CN": "第 1276641 号商标 — 注册证书(俄罗斯 FIPS/Rospatent 网站)",
+}
+
+
+class BrandingParser(HTMLParser):
+ """Collect public header logos and accessible certificate links."""
+
+ def __init__(self):
+ """Initialize independent state for one HTML document."""
+
+ super().__init__()
+ self.lang = "en"
+ self.has_header = False
+ self.logos = []
+ self.links = []
+ self.current_link = None
+ self.in_brand_button = False
+ self.button_images = []
+
+ def handle_starttag(self, tag, attrs):
+ """Collect branding attributes without relying on source indentation."""
+
+ attrs = dict(attrs)
+ classes = attrs.get("class", "").split()
+
+ if tag == "html":
+ self.lang = attrs.get("lang", "en")
+
+ if tag == "header" and "site-header" in classes:
+ self.has_header = True
+
+ if tag == "img" and "FuzzyTechnologies-Logo-" in attrs.get("src", ""):
+ self.logos.append(attrs)
+
+ if tag == "a" and "brand-button" in classes:
+ self.in_brand_button = True
+
+ if tag == "img" and self.in_brand_button:
+ self.button_images.append(attrs)
+
+ if tag == "a" and "trademark-link" in classes:
+ self.current_link = {"attrs": attrs, "text": "", "superscript": False}
+ self.links.append(self.current_link)
+
+ if tag == "sup" and self.current_link is not None:
+ self.current_link["superscript"] = "trademark-symbol" in classes
+
+ def handle_startendtag(self, tag, attrs):
+ """Support both HTML and XHTML image serialization."""
+
+ self.handle_starttag(tag, attrs)
+
+ def handle_endtag(self, tag):
+ """Stop collecting the certificate link's visible text at its boundary."""
+
+ if tag == "a":
+ self.current_link = None
+ self.in_brand_button = False
+
+ def handle_data(self, data):
+ """Capture the full linked brand name, including its registration mark."""
+
+ if self.current_link is not None:
+ self.current_link["text"] += data
+
+
+def ValidatePage(path):
+ """Return failures for branded pages; ignore legacy redirect documents."""
+
+ parser = BrandingParser()
+ parser.feed(path.read_text(encoding="utf-8"))
+
+ if not parser.has_header:
+ return None
+
+ errors = []
+
+ if len(parser.logos) != 1 or parser.logos[0].get("src") != LOGO_URL:
+ errors.append("header must use the registered logo exactly once")
+
+ if len(parser.button_images) != 1 or parser.button_images[0].get("src") != LOGO_URL:
+ errors.append("brand button must wrap only its logo; check inline include whitespace")
+
+ if len(parser.links) != 1:
+ errors.append("footer must contain exactly one certificate link")
+
+ else:
+ link = parser.links[0]
+ attrs = link["attrs"]
+ hint = HINTS.get(parser.lang)
+
+ if attrs.get("href") != CERTIFICATE_URL:
+ errors.append("certificate URL does not match the registered document")
+
+ if not hint or attrs.get("title") != hint or attrs.get("aria-description") != hint:
+ errors.append("certificate tooltip and accessible description must match the page language")
+
+ if link["text"].strip() != "Fuzzy Technologies®" or not link["superscript"]:
+ errors.append("full linked brand name must include a superscript registration mark")
+
+ return errors
+
+
+def Main():
+ """Check the build directory and fail on missing or inconsistent branding."""
+
+ cli = argparse.ArgumentParser(description=__doc__)
+ cli.add_argument("site_dir", type=Path)
+ args = cli.parse_args()
+ checked = 0
+ failures = []
+
+ for path in sorted(args.site_dir.rglob("*.html")):
+ errors = ValidatePage(path)
+
+ if errors is None:
+ continue
+
+ checked += 1
+ failures.extend(f"{path}: {error}" for error in errors)
+
+ if not checked:
+ failures.append("No branded pages found; check the build directory.")
+
+ if failures:
+ raise SystemExit("\n".join(failures))
+
+ print(f"PASS: {checked} pages use registered branding and localized certificate links.")
+
+
+if __name__ == "__main__":
+ Main()
diff --git a/zh-cn/FMA/index.md b/zh-cn/FMA/index.md
index 12b4cfb..82c9d2f 100644
--- a/zh-cn/FMA/index.md
+++ b/zh-cn/FMA/index.md
@@ -17,7 +17,7 @@ alternate_zh: /zh-cn/FMA/
简中
-
+ {% include brand-logo.html %}
@@ -158,8 +158,4 @@ FMA 建立在工程数学和明确的数据处理规则之上:
> **FMA:数学、工程与真实市场——不靠“神奇承诺”。**
-
+{% include site-footer.html %}
diff --git a/zh-cn/FMA/instruments.md b/zh-cn/FMA/instruments.md
index e0319af..d8cea79 100644
--- a/zh-cn/FMA/instruments.md
+++ b/zh-cn/FMA/instruments.md
@@ -17,7 +17,7 @@ alternate_zh: /zh-cn/FMA/instruments.html
简中
-
+ {% include brand-logo.html %}
@@ -93,8 +93,4 @@ MDMG, LIFE, GECO, OZPH, ABIO, PRMD, GEMC.
| PLTRUB_TOM | rub | 铂金 |
| PLDRUB_TOM | rub | 钯金 |
-
+{% include site-footer.html %}
diff --git a/zh-cn/FuzzyRoutines/index.md b/zh-cn/FuzzyRoutines/index.md
index 5186d6f..20c545a 100644
--- a/zh-cn/FuzzyRoutines/index.md
+++ b/zh-cn/FuzzyRoutines/index.md
@@ -19,7 +19,7 @@ alternate_zh: /zh-cn/FuzzyRoutines/
简中
-
+ {% include brand-logo.html %}
@@ -100,8 +100,4 @@ FuzzyRoutines 采用 Apache-2.0 许可证。PyPI 上的稳定版本为 `2.0.0`
- [测试](https://github.com/Fuzzy-Technologies/FuzzyRoutines/tree/master/tests)
- [Apache-2.0 许可证](https://github.com/Fuzzy-Technologies/FuzzyRoutines/blob/master/LICENSE)
-
+{% include site-footer.html %}
diff --git a/zh-cn/index.md b/zh-cn/index.md
index e315cb2..b4eedc7 100644
--- a/zh-cn/index.md
+++ b/zh-cn/index.md
@@ -10,7 +10,7 @@ alternate_zh: /zh-cn/
---
@@ -135,8 +135,4 @@ alternate_zh: /zh-cn/
-
+{% include site-footer.html %}