feat(python): add native distribution and release infrastructure

- add the Rust-backed Python API with PyStemmer compatibility
- distribute standard compiled models as a separate Python package
- generate model artifacts during builds instead of storing them in Git
- add GitHub release and Pages-backed package index workflows
- add Python tests, benchmarks, documentation, and Gradle integration
- refresh the documentation site, branding, and language benchmarks
This commit is contained in:
2026-08-10 22:34:32 +02:00
parent b45e143c84
commit 5e3d3c7c7d
139 changed files with 11420 additions and 747 deletions

View File

@@ -0,0 +1,50 @@
{
"source": "Python all-language batch benchmark, 2026-08-08",
"environment": {
"processor": "AMD Ryzen 5 5625U with Radeon Graphics",
"platform": "Linux-7.1.6-201.fc44.x86_64-x86_64-with-glibc2.43",
"python": "CPython 3.14.6",
"cpu_governor": "schedutil"
},
"batch_size": 100,
"direct_pystemmer_comparisons": 18,
"direct_pystemmer_wins": 18,
"geometric_mean_speedup_vs_pystemmer": 1.665046904842523,
"maximum_speedup_vs_pystemmer": {
"language": "it",
"speedup": 3.027396185495421
},
"radixor_throughput_mwords_per_second": {
"minimum": {
"language": "ru",
"value": 3.6574304356731138
},
"maximum": {
"language": "pt",
"value": 5.99085795076713
}
},
"languages": {
"cs": {"radixor_ns_per_word": 224.3, "radixor_mwords_per_second": 4.46, "pystemmer_ns_per_word": 236.6, "speedup_vs_pystemmer": 1.05},
"da": {"radixor_ns_per_word": 178.3, "radixor_mwords_per_second": 5.61, "pystemmer_ns_per_word": 267.6, "speedup_vs_pystemmer": 1.50},
"de": {"radixor_ns_per_word": 230.9, "radixor_mwords_per_second": 4.33, "pystemmer_ns_per_word": 635.5, "speedup_vs_pystemmer": 2.75},
"en": {"radixor_ns_per_word": 180.5, "radixor_mwords_per_second": 5.54, "pystemmer_ns_per_word": 331.9, "speedup_vs_pystemmer": 1.84},
"es": {"radixor_ns_per_word": 184.2, "radixor_mwords_per_second": 5.43, "pystemmer_ns_per_word": 316.6, "speedup_vs_pystemmer": 1.72},
"fa": {"radixor_ns_per_word": 210.1, "radixor_mwords_per_second": 4.76, "pystemmer_ns_per_word": 497.1, "speedup_vs_pystemmer": 2.37},
"fi": {"radixor_ns_per_word": 227.8, "radixor_mwords_per_second": 4.39, "pystemmer_ns_per_word": 258.8, "speedup_vs_pystemmer": 1.14},
"fr": {"radixor_ns_per_word": 234.2, "radixor_mwords_per_second": 4.27, "pystemmer_ns_per_word": 503.7, "speedup_vs_pystemmer": 2.15},
"he": {"radixor_ns_per_word": 228.6, "radixor_mwords_per_second": 4.37, "pystemmer_ns_per_word": null, "speedup_vs_pystemmer": null},
"hu": {"radixor_ns_per_word": 198.2, "radixor_mwords_per_second": 5.04, "pystemmer_ns_per_word": 264.7, "speedup_vs_pystemmer": 1.34},
"it": {"radixor_ns_per_word": 170.8, "radixor_mwords_per_second": 5.86, "pystemmer_ns_per_word": 517.0, "speedup_vs_pystemmer": 3.03},
"nb": {"radixor_ns_per_word": 187.1, "radixor_mwords_per_second": 5.34, "pystemmer_ns_per_word": 239.7, "speedup_vs_pystemmer": 1.28},
"nl": {"radixor_ns_per_word": 187.1, "radixor_mwords_per_second": 5.35, "pystemmer_ns_per_word": 354.8, "speedup_vs_pystemmer": 1.90},
"nn": {"radixor_ns_per_word": 168.7, "radixor_mwords_per_second": 5.93, "pystemmer_ns_per_word": 231.2, "speedup_vs_pystemmer": 1.37},
"pl": {"radixor_ns_per_word": 194.6, "radixor_mwords_per_second": 5.14, "pystemmer_ns_per_word": 214.5, "speedup_vs_pystemmer": 1.10},
"pt": {"radixor_ns_per_word": 166.9, "radixor_mwords_per_second": 5.99, "pystemmer_ns_per_word": 293.2, "speedup_vs_pystemmer": 1.76},
"ru": {"radixor_ns_per_word": 273.4, "radixor_mwords_per_second": 3.66, "pystemmer_ns_per_word": 414.4, "speedup_vs_pystemmer": 1.52},
"sv": {"radixor_ns_per_word": 189.3, "radixor_mwords_per_second": 5.28, "pystemmer_ns_per_word": 212.5, "speedup_vs_pystemmer": 1.12},
"uk": {"radixor_ns_per_word": 221.5, "radixor_mwords_per_second": 4.51, "pystemmer_ns_per_word": null, "speedup_vs_pystemmer": null},
"yi": {"radixor_ns_per_word": 227.5, "radixor_mwords_per_second": 4.39, "pystemmer_ns_per_word": 624.2, "speedup_vs_pystemmer": 2.74}
},
"pystemmer_missing_for_radixor_languages": ["he", "uk"]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 540 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><defs><clipPath id="c"><circle cx="32" cy="32" r="30"/></clipPath></defs><g clip-path="url(#c)"><rect width="64" height="32" fill="#fff"/><rect y="32" width="64" height="32" fill="#d7141a"/><path d="M0 0 34 32 0 64Z" fill="#11457e"/></g><circle cx="32" cy="32" r="30" fill="none" stroke="#d8e2ee" stroke-width="2"/></svg>

After

Width:  |  Height:  |  Size: 381 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><defs><clipPath id="c"><circle cx="32" cy="32" r="30"/></clipPath></defs><g clip-path="url(#c)"><rect width="64" height="64" fill="#c8102e"/><rect x="19" width="8" height="64" fill="#fff"/><rect y="27" width="64" height="8" fill="#fff"/></g><circle cx="32" cy="32" r="30" fill="none" stroke="#d8e2ee" stroke-width="2"/></svg>

After

Width:  |  Height:  |  Size: 385 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><defs><clipPath id="c"><circle cx="32" cy="32" r="30"/></clipPath></defs><g clip-path="url(#c)"><rect width="64" height="22" fill="#111"/><rect y="22" width="64" height="21" fill="#dd0000"/><rect y="43" width="64" height="21" fill="#ffce00"/></g><circle cx="32" cy="32" r="30" fill="none" stroke="#d8e2ee" stroke-width="2"/></svg>

After

Width:  |  Height:  |  Size: 390 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><defs><clipPath id="c"><circle cx="32" cy="32" r="30"/></clipPath></defs><g clip-path="url(#c)"><rect width="64" height="64" fill="#234b9b"/><path d="M0 0 64 64M64 0 0 64" stroke="white" stroke-width="14"/><path d="M0 0 64 64M64 0 0 64" stroke="#d4253f" stroke-width="7"/><path d="M32 0v64M0 32h64" stroke="white" stroke-width="18"/><path d="M32 0v64M0 32h64" stroke="#d4253f" stroke-width="10"/></g><circle cx="32" cy="32" r="30" fill="none" stroke="#d8e2ee" stroke-width="2"/></svg>

After

Width:  |  Height:  |  Size: 544 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><defs><clipPath id="c"><circle cx="32" cy="32" r="30"/></clipPath></defs><g clip-path="url(#c)"><rect width="64" height="64" fill="#aa151b"/><rect y="16" width="64" height="32" fill="#f1bf00"/><circle cx="23" cy="32" r="4" fill="#aa151b"/></g><circle cx="32" cy="32" r="30" fill="none" stroke="#d8e2ee" stroke-width="2"/></svg>

After

Width:  |  Height:  |  Size: 387 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><defs><clipPath id="c"><circle cx="32" cy="32" r="30"/></clipPath></defs><g clip-path="url(#c)"><rect width="64" height="22" fill="#239f40"/><rect y="22" width="64" height="20" fill="#fff"/><rect y="42" width="64" height="22" fill="#da0000"/><circle cx="32" cy="32" r="5" fill="none" stroke="#da0000" stroke-width="2"/></g><circle cx="32" cy="32" r="30" fill="none" stroke="#d8e2ee" stroke-width="2"/></svg>

After

Width:  |  Height:  |  Size: 467 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><defs><clipPath id="c"><circle cx="32" cy="32" r="30"/></clipPath></defs><g clip-path="url(#c)"><rect width="64" height="64" fill="#fff"/><rect x="19" width="9" height="64" fill="#003580"/><rect y="27" width="64" height="9" fill="#003580"/></g><circle cx="32" cy="32" r="30" fill="none" stroke="#d8e2ee" stroke-width="2"/></svg>

After

Width:  |  Height:  |  Size: 388 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><defs><clipPath id="c"><circle cx="32" cy="32" r="30"/></clipPath></defs><g clip-path="url(#c)"><rect width="22" height="64" fill="#0055a4"/><rect x="22" width="20" height="64" fill="#fff"/><rect x="42" width="22" height="64" fill="#ef4135"/></g><circle cx="32" cy="32" r="30" fill="none" stroke="#d8e2ee" stroke-width="2"/></svg>

After

Width:  |  Height:  |  Size: 390 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><defs><clipPath id="c"><circle cx="32" cy="32" r="30"/></clipPath></defs><g clip-path="url(#c)"><rect width="64" height="64" fill="#fff"/><rect y="13" width="64" height="6" fill="#0038b8"/><rect y="45" width="64" height="6" fill="#0038b8"/><path d="M32 22 39 35H25Zm0 20-7-13h14Z" fill="none" stroke="#0038b8" stroke-width="2.3"/></g><circle cx="32" cy="32" r="30" fill="none" stroke="#d8e2ee" stroke-width="2"/></svg>

After

Width:  |  Height:  |  Size: 478 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><defs><clipPath id="c"><circle cx="32" cy="32" r="30"/></clipPath></defs><g clip-path="url(#c)"><rect width="64" height="22" fill="#ce2939"/><rect y="22" width="64" height="20" fill="#fff"/><rect y="42" width="64" height="22" fill="#477050"/></g><circle cx="32" cy="32" r="30" fill="none" stroke="#d8e2ee" stroke-width="2"/></svg>

After

Width:  |  Height:  |  Size: 390 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><defs><clipPath id="c"><circle cx="32" cy="32" r="30"/></clipPath></defs><g clip-path="url(#c)"><rect width="22" height="64" fill="#009246"/><rect x="22" width="20" height="64" fill="#fff"/><rect x="42" width="22" height="64" fill="#ce2b37"/></g><circle cx="32" cy="32" r="30" fill="none" stroke="#d8e2ee" stroke-width="2"/></svg>

After

Width:  |  Height:  |  Size: 390 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><defs><clipPath id="c"><circle cx="32" cy="32" r="30"/></clipPath></defs><g clip-path="url(#c)"><rect width="64" height="64" fill="#ba0c2f"/><rect x="18" width="12" height="64" fill="#fff"/><rect y="25" width="64" height="12" fill="#fff"/><rect x="21" width="6" height="64" fill="#00205b"/><rect y="28" width="64" height="6" fill="#00205b"/></g><circle cx="32" cy="32" r="30" fill="none" stroke="#d8e2ee" stroke-width="2"/></svg>

After

Width:  |  Height:  |  Size: 489 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><defs><clipPath id="c"><circle cx="32" cy="32" r="30"/></clipPath></defs><g clip-path="url(#c)"><rect width="64" height="22" fill="#ae1c28"/><rect y="22" width="64" height="20" fill="#fff"/><rect y="42" width="64" height="22" fill="#21468b"/></g><circle cx="32" cy="32" r="30" fill="none" stroke="#d8e2ee" stroke-width="2"/></svg>

After

Width:  |  Height:  |  Size: 390 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><defs><clipPath id="c"><circle cx="32" cy="32" r="30"/></clipPath></defs><g clip-path="url(#c)"><rect width="64" height="64" fill="#ba0c2f"/><rect x="18" width="12" height="64" fill="#fff"/><rect y="25" width="64" height="12" fill="#fff"/><rect x="21" width="6" height="64" fill="#00205b"/><rect y="28" width="64" height="6" fill="#00205b"/></g><circle cx="32" cy="32" r="30" fill="none" stroke="#d8e2ee" stroke-width="2"/></svg>

After

Width:  |  Height:  |  Size: 489 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><defs><clipPath id="c"><circle cx="32" cy="32" r="30"/></clipPath></defs><g clip-path="url(#c)"><rect width="64" height="32" fill="#fff"/><rect y="32" width="64" height="32" fill="#dc143c"/></g><circle cx="32" cy="32" r="30" fill="none" stroke="#d8e2ee" stroke-width="2"/></svg>

After

Width:  |  Height:  |  Size: 338 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><defs><clipPath id="c"><circle cx="32" cy="32" r="30"/></clipPath></defs><g clip-path="url(#c)"><rect width="25" height="64" fill="#046a38"/><rect x="25" width="39" height="64" fill="#da291c"/><circle cx="25" cy="32" r="7" fill="#ffcd00"/><circle cx="25" cy="32" r="4" fill="#fff"/></g><circle cx="32" cy="32" r="30" fill="none" stroke="#d8e2ee" stroke-width="2"/></svg>

After

Width:  |  Height:  |  Size: 430 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><defs><clipPath id="c"><circle cx="32" cy="32" r="30"/></clipPath></defs><g clip-path="url(#c)"><rect width="64" height="22" fill="#fff"/><rect y="22" width="64" height="20" fill="#0039a6"/><rect y="42" width="64" height="22" fill="#d52b1e"/></g><circle cx="32" cy="32" r="30" fill="none" stroke="#d8e2ee" stroke-width="2"/></svg>

After

Width:  |  Height:  |  Size: 390 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><defs><clipPath id="c"><circle cx="32" cy="32" r="30"/></clipPath></defs><g clip-path="url(#c)"><rect width="64" height="64" fill="#006aa7"/><rect x="19" width="8" height="64" fill="#fecc00"/><rect y="27" width="64" height="8" fill="#fecc00"/></g><circle cx="32" cy="32" r="30" fill="none" stroke="#d8e2ee" stroke-width="2"/></svg>

After

Width:  |  Height:  |  Size: 391 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><defs><clipPath id="c"><circle cx="32" cy="32" r="30"/></clipPath></defs><g clip-path="url(#c)"><rect width="64" height="32" fill="#0057b7"/><rect y="32" width="64" height="32" fill="#ffd700"/></g><circle cx="32" cy="32" r="30" fill="none" stroke="#d8e2ee" stroke-width="2"/></svg>

After

Width:  |  Height:  |  Size: 341 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><defs><clipPath id="c"><circle cx="32" cy="32" r="30"/></clipPath></defs><g clip-path="url(#c)"><rect width="64" height="64" fill="#fff"/><rect y="13" width="64" height="6" fill="#0038b8"/><rect y="45" width="64" height="6" fill="#0038b8"/><path d="M32 22 39 35H25Zm0 20-7-13h14Z" fill="none" stroke="#0038b8" stroke-width="2.3"/></g><circle cx="32" cy="32" r="30" fill="none" stroke="#d8e2ee" stroke-width="2"/></svg>

After

Width:  |  Height:  |  Size: 478 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 900 700" fill="none"><defs><linearGradient id="g" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#6759ff" stop-opacity=".10"/><stop offset=".5" stop-color="#2d8cff" stop-opacity=".13"/><stop offset="1" stop-color="#12bfa7" stop-opacity=".10"/></linearGradient></defs><g stroke="url(#g)" stroke-width="1.25"><path d="M-40 585C150 328 262 493 408 255S665 12 927 50"/><path d="M-55 620C142 363 274 507 424 273S689 16 940 78"/><path d="M-65 652C151 403 289 526 447 301S704 34 958 112"/><path d="M-71 679C162 442 311 548 471 336S727 63 970 148"/><path d="M-74 704C186 481 338 574 500 371S748 94 985 190"/><path d="M244 8C400 46 516 22 622 93S780 236 940 227"/><path d="M270 -7C428 28 540 8 655 78S811 209 964 197"/></g><g fill="#0ea5e9" opacity=".18"><circle cx="408" cy="255" r="3.8"/><circle cx="500" cy="371" r="3.8"/><circle cx="655" cy="78" r="3.8"/><circle cx="811" cy="209" r="3.8"/></g></svg>

After

Width:  |  Height:  |  Size: 947 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 220 190" fill="none"><defs><linearGradient id="s" x1="35" y1="25" x2="173" y2="172"><stop stop-color="#8b78ff"/><stop offset=".55" stop-color="#5b49e9"/><stop offset="1" stop-color="#3158f5"/></linearGradient><filter id="f"><feDropShadow dx="0" dy="8" stdDeviation="8" flood-color="#4f46e5" flood-opacity=".18"/></filter></defs><g stroke="#7667f2" stroke-width="5" stroke-linecap="round" fill="none" opacity=".8"><path d="M49 143c-23-9-32-25-37-45M42 127c-12-3-21-11-26-21M171 143c23-9 32-25 37-45M178 127c12-3 21-11 26-21"/><path d="M51 144c-17 6-28 7-38 5M169 144c17 6 28 7 38 5"/></g><path filter="url(#f)" d="M110 18 168 42v52c0 41-25 66-58 82-33-16-58-41-58-82V42Z" fill="url(#s)" stroke="#b7afff" stroke-width="3"/><path d="M88 114h44M96 124h28" stroke="white" stroke-width="5" stroke-linecap="round"/><path d="M90 92c0 12 8 20 20 20s20-8 20-20v-6H90v6Z" fill="none" stroke="white" stroke-width="5"/><path d="M130 88h8c9 0 9 13 0 13h-9" stroke="white" stroke-width="5" stroke-linecap="round"/><path d="M102 79c-13-12 9-16-2-30M115 78c-10-11 8-15 0-27M126 79c-8-9 7-13 0-23" stroke="white" stroke-width="4" stroke-linecap="round"/></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

View File

@@ -0,0 +1 @@
document.addEventListener("DOMContentLoaded",()=>{const b=document.querySelector(".rx2-menu"),n=document.querySelector(".rx2-nav");if(b&&n)b.addEventListener("click",()=>{const o=n.classList.toggle("open");b.setAttribute("aria-expanded",String(o));});document.querySelectorAll("[data-copy]").forEach(btn=>btn.addEventListener("click",async()=>{const el=document.getElementById(btn.dataset.copy);if(!el)return;try{await navigator.clipboard.writeText(el.innerText);const t=btn.textContent;btn.textContent="Copied";setTimeout(()=>btn.textContent=t,1200);}catch(e){}}));});

View File

@@ -0,0 +1,14 @@
const renderRadixorDiagrams = () => {
mermaid.initialize({
startOnLoad: false,
theme: "neutral",
flowchart: { htmlLabels: true, useMaxWidth: true },
});
return mermaid.run({ querySelector: ".mermaid" });
};
if (typeof document$ === "undefined") {
document.addEventListener("DOMContentLoaded", renderRadixorDiagrams);
} else {
document$.subscribe(renderRadixorDiagrams);
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,146 @@
/*
* Radixor documentation safety constraints.
*
* The landing page uses custom page chrome while standard documentation pages
* use Material for MkDocs. These size constraints ensure that a documentation
* logo can never inherit unconstrained intrinsic dimensions. The remaining
* rules carry the landing page's light blue/teal visual language into the
* standard Material documentation shell.
*/
:root,
[data-md-color-scheme="default"] {
--md-primary-fg-color: #ffffff;
--md-primary-fg-color--light: #ffffff;
--md-primary-fg-color--dark: #f7faff;
--md-primary-bg-color: #11182e;
--md-primary-bg-color--light: #4b5b74;
--md-accent-fg-color: #1769ef;
--md-accent-fg-color--transparent: rgba(23, 105, 239, 0.1);
--md-typeset-a-color: #0e62df;
--rx-doc-line: #dce6f2;
--rx-doc-soft: #f7faff;
--rx-doc-text: #172554;
--rx-doc-muted: #53627b;
--rx-doc-teal: #078d7a;
--rx-doc-purple: #6544ef;
}
.md-header {
color: var(--rx-doc-text);
background: rgba(255, 255, 255, 0.97);
border-bottom: 1px solid var(--rx-doc-line);
box-shadow: 0 5px 18px rgba(33, 64, 112, 0.06);
backdrop-filter: blur(8px);
}
.md-header__title,
.md-header__button,
.md-header__topic,
.md-source {
color: var(--rx-doc-text);
}
.md-search__form {
background: #f3f7fc;
border: 1px solid #d8e4f0;
}
.md-search__input,
.md-search__icon {
color: var(--rx-doc-text);
}
.md-search__input::placeholder {
color: #69778d;
}
.md-tabs {
color: var(--rx-doc-text);
background: #fbfdff;
border-bottom: 1px solid var(--rx-doc-line);
}
.md-nav__link--active,
.md-nav__link:focus,
.md-nav__link:hover {
color: #145ff5;
}
.md-nav__item--section > .md-nav__link {
color: #263653;
}
.md-typeset h1,
.md-typeset h2,
.md-typeset h3 {
color: #0b1537;
}
.md-typeset a:hover {
color: var(--rx-doc-purple);
}
.md-typeset code {
border-radius: 0.22rem;
background: #f3f7fc;
}
.md-typeset .admonition,
.md-typeset details {
border-color: #8bb6f2;
box-shadow: 0 3px 12px rgba(33, 64, 112, 0.06);
}
.md-typeset table:not([class]) {
border-color: var(--rx-doc-line);
box-shadow: 0 2px 10px rgba(33, 64, 112, 0.04);
}
.md-footer {
--md-footer-fg-color: var(--rx-doc-text);
--md-footer-fg-color--light: #31516f;
--md-footer-fg-color--lighter: var(--rx-doc-muted);
--md-footer-bg-color: #fbfdff;
--md-footer-bg-color--dark: #f5f9fe;
color: var(--rx-doc-muted);
background: #fbfdff;
border-top: 1px solid var(--rx-doc-line);
}
.md-footer-meta {
color: var(--rx-doc-muted);
background: #f5f9fe;
}
.md-footer a,
.md-footer-meta a {
color: #31516f;
}
.md-header__button.md-logo img,
.md-header__button.md-logo svg,
.md-nav__button.md-logo img,
.md-nav__button.md-logo svg {
width: 1.6rem;
height: 1.6rem;
max-width: 1.6rem;
max-height: 1.6rem;
object-fit: cover;
border-radius: 0.38rem;
box-shadow: 0 2px 8px rgba(24, 82, 176, 0.18);
}
.md-typeset .mermaid {
width: 100%;
max-width: 100%;
overflow-x: auto;
text-align: center;
}
.md-typeset .mermaid svg {
display: block;
width: auto;
max-width: 100%;
height: auto;
margin-inline: auto;
}