/) with no
+# version segment. There is intentionally no [versioning] block — version-aware
+# specs detect the absence and skip gracefully (same mechanism agentregistry's
+# and ambientmesh's flat docs rely on).
+
+# All checks default to enabled. No [checks] overrides are needed: kagent runs
+# the full default set. (The former `smoke`/`crossBrowser` toggles were removed
+# from the harness — smoke folded into the `content` project scoped by
+# CONTENT_DIR, and cross-browser is now selected per Playwright project.)
+
+# Allowlists for known-benign noise that surfaces against real content (the
+# module's bundled fixture has none of this).
+[allowlists]
+hugoWarnings = [
+ "\\.Site\\.Data was deprecated",
+ "'items' parameter of the 'tabs' shortcode is deprecated",
+]
+# consoleErrors is intentionally empty: CI runs only the static + content
+# projects, which don't launch the third-party page scripts. Populate this when
+# the browser / console-error projects are enabled for kagent (they'll surface
+# the analytics/search backends that fail in the offline test environment). The
+# Hextra main.js null-deref that other consumers allowlisted here does NOT occur:
+# docs-theme-extras' module footer renders the hidden hamburger/sidebar stand-ins
+# site-wide (confirmed present on the built docs pages after the beta.4 bump).
+consoleErrors = []
diff --git a/docs-site/.gitignore b/docs-site/.gitignore
new file mode 100644
index 00000000..d2c815ce
--- /dev/null
+++ b/docs-site/.gitignore
@@ -0,0 +1,6 @@
+/public/
+/resources/
+/node_modules/
+/hugo_stats.json
+.hugo_build.lock
+.DS_Store
diff --git a/docs-site/assets/css/chatbot.css b/docs-site/assets/css/chatbot.css
new file mode 100644
index 00000000..5c755f69
--- /dev/null
+++ b/docs-site/assets/css/chatbot.css
@@ -0,0 +1,497 @@
+/* Chatbot CSS - Animations and Dynamic Content Styling */
+
+/* ===== Animations ===== */
+@keyframes dialogSlideIn {
+ from {
+ opacity: 0;
+ transform: scale(0.95) translateY(10px);
+ }
+ to {
+ opacity: 1;
+ transform: scale(1) translateY(0);
+ }
+}
+
+@keyframes messageSlideIn {
+ from {
+ opacity: 0;
+ transform: translateY(8px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+@keyframes spin {
+ to {
+ transform: rotate(360deg);
+ }
+}
+
+@keyframes bounceSingle {
+ 0% {
+ transform: translateY(0);
+ }
+ 50% {
+ transform: translateY(-3px);
+ }
+ 100% {
+ transform: translateY(0);
+ }
+}
+
+@keyframes blink {
+ 0%, 50% { opacity: 1; }
+ 51%, 100% { opacity: 0; }
+}
+
+
+@keyframes codeLine {
+ from {
+ opacity: 0;
+ transform: translateY(-2px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+/* ===== Component States ===== */
+.chatbot-dialog.expanded {
+ height: 80vh;
+}
+
+/* Unified input card focus glow */
+.chatbot-input-card:focus-within {
+ border-color: #8b5cf6;
+ box-shadow: 0 0 0 2px rgba(139, 92, 246, 0.15);
+}
+
+/* User message - shrink-wrap to text content */
+.chatbot-message.user {
+ width: fit-content;
+ max-width: 100%;
+ word-break: break-word;
+ overflow-wrap: break-word;
+ background: linear-gradient(135deg, #7c3aed, #6d28d9);
+ color: #fff;
+ box-shadow: 0 2px 8px rgba(124, 58, 237, 0.2);
+}
+
+.dark .chatbot-message.user {
+ box-shadow: 0 2px 8px rgba(124, 58, 237, 0.3);
+}
+
+/* ===== Avatar Loading Animation ===== */
+.chatbot-avatar.loading img {
+ width: 75%;
+ height: 75%;
+}
+
+.chatbot-avatar.loading::after {
+ content: '';
+ position: absolute;
+ inset: 0;
+ border-radius: 30px;
+ border: 2px solid transparent;
+ border-top-color: #7c3aed;
+ border-right-color: #7c3aed;
+ animation: spin 0.8s linear infinite;
+}
+
+.dark .chatbot-avatar.loading::after {
+ border-top-color: #a78bfa;
+ border-right-color: #a78bfa;
+}
+
+/* ===== Thinking Animation ===== */
+.thinking-dots {
+ color: #7c3aed;
+ font-size: 1.5rem;
+}
+
+.dark .thinking-dots {
+ color: #a78bfa;
+}
+
+.thinking-dots .dot {
+ display: inline-block;
+ transition: transform 0.3s ease-in-out;
+}
+
+.thinking-dots .dot.bouncing {
+ animation: bounceSingle 0.6s ease-in-out;
+}
+
+/* ===== Code Block Animations ===== */
+.chatbot-code-cursor {
+ display: inline-block;
+ width: 8px;
+ height: 1em;
+ background: #7c3aed;
+ margin-left: 2px;
+ vertical-align: text-bottom;
+ animation: blink 1s step-end infinite;
+}
+
+.dark .chatbot-code-cursor {
+ background: #a78bfa;
+}
+
+.chatbot-code-line {
+ display: block;
+ animation: codeLine 0.15s ease-out forwards;
+}
+
+/* ===== Scrollbar Styling ===== */
+.chatbot-messages {
+ scrollbar-width: thin;
+ scrollbar-color: rgba(156, 163, 175, 0.3) transparent;
+}
+
+.chatbot-messages::-webkit-scrollbar {
+ width: 6px;
+}
+
+.chatbot-messages::-webkit-scrollbar-track {
+ background: transparent;
+}
+
+.chatbot-messages::-webkit-scrollbar-thumb {
+ background: rgba(156, 163, 175, 0.3);
+ border-radius: 3px;
+}
+
+.chatbot-messages::-webkit-scrollbar-thumb:hover {
+ background: rgba(156, 163, 175, 0.5);
+}
+
+.dark .chatbot-messages {
+ scrollbar-color: rgba(107, 114, 128, 0.3) transparent;
+}
+
+.dark .chatbot-messages::-webkit-scrollbar-thumb {
+ background: rgba(107, 114, 128, 0.3);
+}
+
+.dark .chatbot-messages::-webkit-scrollbar-thumb:hover {
+ background: rgba(107, 114, 128, 0.5);
+}
+
+textarea {
+ scrollbar-width: thin;
+ scrollbar-color: rgba(156, 163, 175, 0.3) transparent;
+}
+
+textarea::-webkit-scrollbar {
+ width: 6px;
+}
+
+textarea::-webkit-scrollbar-track {
+ background: transparent;
+}
+
+textarea::-webkit-scrollbar-thumb {
+ background: rgba(156, 163, 175, 0.3);
+ border-radius: 3px;
+}
+
+textarea::-webkit-scrollbar-thumb:hover {
+ background: rgba(156, 163, 175, 0.5);
+}
+
+.dark textarea {
+ scrollbar-color: rgba(107, 114, 128, 0.3) transparent;
+}
+
+.dark textarea::-webkit-scrollbar-thumb {
+ background: rgba(107, 114, 128, 0.3);
+}
+
+.dark textarea::-webkit-scrollbar-thumb:hover {
+ background: rgba(107, 114, 128, 0.5);
+}
+
+/* ===== Markdown Content Styling ===== */
+.chatbot-response {
+ font-size: 0.875rem;
+ line-height: 1.6;
+ color: #111827;
+}
+
+.dark .chatbot-response {
+ color: #e5e7eb;
+}
+
+.chatbot-response h1,
+.chatbot-response h2,
+.chatbot-response h3,
+.chatbot-response h4 {
+ margin-top: 1.25rem;
+ margin-bottom: 0.5rem;
+ font-weight: 600;
+ line-height: 1.3;
+ color: #111827;
+}
+
+.dark .chatbot-response h1,
+.dark .chatbot-response h2,
+.dark .chatbot-response h3,
+.dark .chatbot-response h4 {
+ color: #f9fafb;
+}
+
+.chatbot-response h1 { font-size: 1.375rem; }
+.chatbot-response h2 { font-size: 1.25rem; }
+.chatbot-response h3 { font-size: 1.125rem; }
+.chatbot-response h4 { font-size: 1rem; }
+
+.chatbot-response h1:first-child,
+.chatbot-response h2:first-child,
+.chatbot-response h3:first-child,
+.chatbot-response h4:first-child {
+ margin-top: 0;
+}
+
+.chatbot-response p {
+ margin: 0.625rem 0;
+}
+
+.chatbot-response p:first-child {
+ margin-top: 0;
+}
+
+.chatbot-response p:last-child {
+ margin-bottom: 0;
+}
+
+.chatbot-response ul,
+.chatbot-response ol {
+ margin: 0.625rem 0;
+ padding-left: 1.5rem;
+}
+
+.chatbot-response li {
+ margin: 0.25rem 0;
+}
+
+.chatbot-response code {
+ background: #f3f4f6;
+ padding: 0.125rem 0.375rem;
+ border-radius: 4px;
+ font-size: 0.875em;
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
+ border: none;
+}
+
+.dark .chatbot-response code {
+ background: #374151;
+}
+
+.chatbot-response pre {
+ background: #f6f8fa;
+ border: 1px solid #e5e7eb;
+ border-radius: 8px;
+ padding: 1rem;
+ overflow-x: auto;
+ margin: 0.75rem 0;
+}
+
+.dark .chatbot-response pre {
+ background: #0d1117;
+ border-color: #30363d;
+}
+
+.chatbot-response pre code {
+ background: transparent;
+ padding: 0;
+ font-size: 0.8125rem;
+ line-height: 1.5;
+ color: #24292f;
+ border: none;
+ border-radius: 0;
+ display: block;
+}
+
+.dark .chatbot-response pre code {
+ color: #e6edf3;
+ background: transparent;
+ border: none;
+}
+
+.chatbot-response blockquote {
+ border-left: 3px solid #7c3aed;
+ padding-left: 1rem;
+ margin: 0.75rem 0;
+ color: #6b7280;
+}
+
+.dark .chatbot-response blockquote {
+ color: #9ca3af;
+}
+
+.chatbot-response a {
+ color: #7c3aed;
+ text-decoration: none;
+}
+
+.chatbot-response a:hover {
+ text-decoration: underline;
+}
+
+.chatbot-response table {
+ border-collapse: collapse;
+ width: 100%;
+ margin: 0.75rem 0;
+ font-size: 0.875rem;
+}
+
+.chatbot-response th,
+.chatbot-response td {
+ border: 1px solid #e5e7eb;
+ padding: 0.5rem 0.75rem;
+ text-align: left;
+}
+
+.dark .chatbot-response th,
+.dark .chatbot-response td {
+ border-color: #374151;
+}
+
+.chatbot-response th {
+ background: #f9fafb;
+ font-weight: 600;
+}
+
+.dark .chatbot-response th {
+ background: #1f2937;
+}
+
+.chatbot-response hr {
+ border: none;
+ border-top: 1px solid #e5e7eb;
+ margin: 1rem 0;
+}
+
+.dark .chatbot-response hr {
+ border-top-color: #374151;
+}
+
+/* ===== Code Copy Button ===== */
+.chatbot-code-block {
+ position: relative;
+}
+
+.chatbot-code-copy {
+ position: absolute;
+ top: 0.5rem;
+ right: 0.5rem;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 1.75rem;
+ height: 1.75rem;
+ background: rgba(255, 255, 255, 0.9);
+ border: 1px solid #e5e7eb;
+ border-radius: 6px;
+ color: #6b7280;
+ cursor: pointer;
+ opacity: 0;
+ transition: opacity 0.15s, color 0.15s, background 0.15s;
+ z-index: 1;
+}
+
+.chatbot-code-block:hover .chatbot-code-copy {
+ opacity: 1;
+}
+
+.chatbot-code-copy:hover,
+.chatbot-code-copy.copied {
+ color: #7c3aed;
+ background: #fff;
+}
+
+.dark .chatbot-code-copy {
+ background: rgba(17, 24, 39, 0.9);
+ border-color: #374151;
+ color: #9ca3af;
+}
+
+.dark .chatbot-code-block:hover .chatbot-code-copy {
+ opacity: 1;
+}
+
+.dark .chatbot-code-copy:hover,
+.dark .chatbot-code-copy.copied {
+ color: #a78bfa;
+ background: #111827;
+}
+
+/* ===== @ Mention Autocomplete ===== */
+.chatbot-mention-menu {
+ max-height: 280px;
+}
+
+.chatbot-mention-list {
+ scrollbar-width: thin;
+ scrollbar-color: rgba(156, 163, 175, 0.3) transparent;
+}
+
+.chatbot-mention-list::-webkit-scrollbar {
+ width: 5px;
+}
+
+.chatbot-mention-list::-webkit-scrollbar-track {
+ background: transparent;
+}
+
+.chatbot-mention-list::-webkit-scrollbar-thumb {
+ background: rgba(156, 163, 175, 0.3);
+ border-radius: 3px;
+}
+
+.chatbot-mention-list::-webkit-scrollbar-thumb:hover {
+ background: rgba(156, 163, 175, 0.5);
+}
+
+.dark .chatbot-mention-list {
+ scrollbar-color: rgba(107, 114, 128, 0.3) transparent;
+}
+
+.dark .chatbot-mention-list::-webkit-scrollbar-thumb {
+ background: rgba(107, 114, 128, 0.3);
+}
+
+.dark .chatbot-mention-list::-webkit-scrollbar-thumb:hover {
+ background: rgba(107, 114, 128, 0.5);
+}
+
+.chatbot-mention-item.active,
+.chatbot-mention-item:hover {
+ background: #f5f3ff;
+}
+
+.dark .chatbot-mention-item.active,
+.dark .chatbot-mention-item:hover {
+ background: rgba(139, 92, 246, 0.1);
+}
+
+/* ===== Responsive Overrides ===== */
+@media (max-width: 640px) {
+ .chatbot-dialog {
+ height: 60vh;
+ max-height: 95vh;
+ border-radius: 12px;
+ }
+
+ .chatbot-dialog.expanded {
+ height: 95vh;
+ }
+
+ .chatbot-avatar {
+ width: 28px;
+ height: 28px;
+ }
+}
diff --git a/docs-site/assets/css/custom.css b/docs-site/assets/css/custom.css
new file mode 100644
index 00000000..1be553e0
--- /dev/null
+++ b/docs-site/assets/css/custom.css
@@ -0,0 +1,487 @@
+/* Sticky side-rail offset (left sidebar + right TOC).
+ extras pins the rails to `--solo-rail-top = --navbar-height + --hextra-banner-height`.
+ The extras navbar is h-24 (6rem), so --navbar-height must be 6rem (Hextra
+ defaults it to 4rem, which tucked the rails under the taller navbar). Hextra
+ also defaults --hextra-banner-height to 2rem assuming an announcement banner;
+ kagent has none, so that 2rem was phantom space pushing both rails ~2rem below
+ the content column. Zero it so the rails line up with the breadcrumb/content. */
+:root {
+ --navbar-height: 6rem;
+ /* Small offset so the sidebar/TOC first lines sit on the breadcrumb line
+ (the breadcrumb row sits ~1.1rem below the content pad). Not a real banner. */
+ --hextra-banner-height: 1.1rem;
+}
+
+/* Horizontal divider between the top nav and page content (matches agw-oss).
+ The extras navbar is transparent with only a soft blur shadow; add an
+ explicit hairline so the nav reads as a distinct bar. */
+.hextra-nav-container {
+ border-bottom: 1px solid #e5e7eb;
+}
+.dark .hextra-nav-container {
+ border-bottom-color: #374151;
+}
+
+/* Theme-toggle icon visibility — explicit fallback for the Tailwind v4
+ hx:group-data-[theme=*]:hidden variant. The v4 rule uses :is()/:where()
+ which can lose the battle against Tailwind v3's svg{display:block} preflight
+ when both pipelines run. This direct descendant selector with !important
+ guarantees only the current-theme icon renders. */
+.hx\:group[data-theme="light"] .hx\:group-data-\[theme\=light\]\:hidden,
+.hx\:group[data-theme="dark"] .hx\:group-data-\[theme\=dark\]\:hidden,
+.hx\:group[data-theme="system"] .hx\:group-data-\[theme\=system\]\:hidden {
+ display: none !important;
+}
+
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ font-family: 'Open Sans', 'ui-sans-serif', 'system-ui', 'sans-serif', "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
+}
+
+.nav-container {
+ font-family: 'Open Sans', 'ui-sans-serif', 'system-ui', 'sans-serif', "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
+}
+
+/* Test Status Badge - Modern gradient style */
+.test-status-badge {
+ position: relative;
+ display: inline-flex;
+ align-items: center;
+ gap: 0.4rem;
+ padding: 0.3rem 0.75rem;
+ border: 1px solid #d1d5db;
+ border-radius: 6px;
+ font-size: 0.7rem;
+ font-weight: 600;
+ line-height: 1;
+ margin-top: 0.5rem;
+ margin-bottom: 1rem;
+ letter-spacing: 0.03em;
+ text-transform: none;
+ transition: all 0.2s ease;
+ cursor: default;
+}
+
+.test-status-passed {
+ background: none;
+ color: #111827;
+ box-shadow: none;
+}
+
+.test-status-passed:hover {
+ transform: translateY(-1px);
+}
+
+.test-status-passed .test-status-icon {
+ fill: #059669;
+}
+
+.dark .test-status-passed {
+ background: none;
+ color: #f9fafb;
+ box-shadow: none;
+ border-color: #9ca3af;
+}
+
+.dark .test-status-passed:hover {
+ box-shadow: none;
+}
+
+.dark .test-status-passed .test-status-icon {
+ fill: #34d399;
+}
+
+.test-status-icon {
+ width: 0.7rem;
+ height: 0.7rem;
+ fill: currentColor;
+ flex-shrink: 0;
+}
+
+.test-status-text {
+ white-space: nowrap;
+}
+
+/* Modern tooltip */
+.test-status-tooltip {
+ position: absolute;
+ left: 50%;
+ top: 100%;
+ transform: translateX(-50%) translateY(8px);
+ padding: 0.5rem 0.75rem;
+ background: #1f2937;
+ color: #ffffff;
+ font-size: 0.8rem;
+ font-weight: 500;
+ line-height: 1.4;
+ letter-spacing: normal;
+ text-transform: none;
+ white-space: nowrap;
+ border-radius: 6px;
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15), 0 2px 4px rgba(0, 0, 0, 0.1);
+ opacity: 0;
+ visibility: hidden;
+ transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
+ z-index: 50;
+ pointer-events: none;
+}
+
+.test-status-tooltip::before {
+ content: '';
+ position: absolute;
+ left: 50%;
+ bottom: 100%;
+ transform: translateX(-50%);
+ border: 6px solid transparent;
+ border-bottom-color: #1f2937;
+}
+
+.test-status-badge:hover .test-status-tooltip {
+ opacity: 1;
+ visibility: visible;
+ transform: translateX(-50%) translateY(6px);
+}
+
+.dark .test-status-tooltip {
+ background: #374151;
+ color: #f3f4f6;
+}
+
+.dark .test-status-tooltip::before {
+ border-bottom-color: #374151;
+}
+
+/* Theme-toggle dropdown — fix checkmark/text overlap.
+ Hextra's hx:ltr:pl-3, hx:ltr:pr-9, hx:py-1.5, and hx:ltr:right-3 live inside
+ @layer utilities in main.css. Tailwind v3's unlayered button { padding:0 }
+ preflight in styles.css beats any @layer rule regardless of specificity, so the
+ right padding that makes room for the checkmark never applies. Override with
+ explicit values here (unlayered + !important beats everything). */
+.hextra-theme-toggle-options button[role="menuitemradio"] {
+ padding-left: 0.75rem !important; /* hx:ltr:pl-3 — 3 × 0.25rem */
+ padding-right: 2.25rem !important; /* hx:ltr:pr-9 — 9 × 0.25rem */
+ padding-top: 0.375rem !important; /* hx:py-1.5 — 1.5 × 0.25rem */
+ padding-bottom: 0.375rem !important;
+}
+.hextra-theme-toggle-options button[role="menuitemradio"] > span {
+ right: 0.75rem !important; /* hx:ltr:right-3 — 3 × 0.25rem */
+}
+
+/* Theme-toggle dropdown container — hx:border and hx:shadow-lg also live in
+ @layer utilities, so the same @layer vs unlayered-preflight conflict applies.
+ Tailwind v3's * { border-width: 0 } erases the dropdown border, and
+ * { --tw-shadow: 0 0 #0000 } zeros the variable used by hx:shadow-lg, so
+ no shadow renders. Dark-mode border color also needs a fix because
+ * { border-color: #e5e7eb } (light gray) beats the layered neutral-700. */
+.hextra-theme-toggle-options {
+ border-width: 1px !important;
+ border-style: solid !important;
+ border-color: var(--hx-color-gray-200) !important;
+ box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1) !important;
+}
+.dark .hextra-theme-toggle-options {
+ border-color: var(--hx-color-neutral-700) !important;
+}
+
+/* Dark mode code block scrollbar track */
+.dark pre::-webkit-scrollbar-track {
+ background: #1e1e1e;
+}
+.dark pre::-webkit-scrollbar {
+ height: 8px;
+}
+.dark pre::-webkit-scrollbar-thumb {
+ background: #444;
+ border-radius: 4px;
+}
+.dark pre {
+ scrollbar-color: #444 #1e1e1e;
+}
+
+.dark .provider-icon-invert-dark {
+ filter: invert(1);
+}
+
+/* Sidebar link styling — match TOC text color */
+.sidebar-link:not(.sidebar-active-item) {
+ color: #6b7280;
+}
+.sidebar-link:not(.sidebar-active-item):hover {
+ color: #111827;
+ background: #f3f4f6;
+}
+.sidebar-link.sidebar-active-item {
+ color: #1e40af;
+ background: #dbeafe;
+}
+.dark .sidebar-link:not(.sidebar-active-item) {
+ color: #9ca3af !important;
+}
+.dark .sidebar-link:not(.sidebar-active-item):hover {
+ color: #e5e7eb !important;
+ background: rgba(255,255,255,0.05) !important;
+}
+.dark .sidebar-link.sidebar-active-item {
+ color: #c7d2fe !important;
+ background: rgba(99,102,241,0.1) !important;
+}
+
+.dark .sidebar-container {
+ background-color: #111 !important;
+}
+.sidebar-nav {
+ color: #6b7280;
+}
+.dark .sidebar-nav {
+ color: #9ca3af !important;
+}
+
+/* Hextra tabs - data-state show/hide and active styling */
+.hextra-tabs-panel {
+ display: none;
+}
+.hextra-tabs-panel[data-state="selected"] {
+ display: block;
+ padding-top: 1.5rem;
+}
+.hextra-tabs-toggle {
+ cursor: pointer;
+ padding: 0.5rem;
+ margin-right: 0.5rem;
+ font-weight: 500;
+ border-bottom: 2px solid transparent;
+ color: #4b5563;
+ background: none;
+ border-top: none;
+ border-left: none;
+ border-right: none;
+ transition: color 0.15s, border-color 0.15s;
+}
+.hextra-tabs-toggle:hover {
+ color: #000;
+ border-bottom-color: #d1d5db;
+}
+.hextra-tabs-toggle[data-state="selected"] {
+ color: hsl(212, 100%, 45%);
+ border-bottom-color: hsl(212, 100%, 50%);
+}
+.dark .hextra-tabs-toggle {
+ color: #d1d5db;
+}
+.dark .hextra-tabs-toggle:hover {
+ color: #fff;
+ border-bottom-color: #4b5563;
+}
+.dark .hextra-tabs-toggle[data-state="selected"] {
+ color: hsl(212, 100%, 60%);
+ border-bottom-color: hsl(212, 100%, 50%);
+}
+
+/* Light/dark image toggling */
+.light-only { display: block; }
+.dark-only { display: none; }
+.dark .light-only { display: none; }
+.dark .dark-only { display: block; }
+
+/* Dark mode: page, sidebar, footer, toc, AND the navbar share one bg (#030712).
+ The navbar's bg lives on .hextra-nav-container-blur, which Hextra hardcodes to
+ var(--hx-color-dark) (#111) with !important — a lighter gray than the page — so
+ it must be listed here (higher specificity + !important) to match. Otherwise
+ the top nav reads as a different shade than the rest of the page in dark mode. */
+.dark body,
+.dark .hextra-footer,
+.dark .sidebar-container,
+.dark .hextra-toc,
+.dark .hextra-nav-container-blur {
+ background-color: #030712 !important;
+}
+
+/* Center all footer content on all screen sizes */
+.hextra-custom-footer {
+ margin-left: auto;
+ margin-right: auto;
+}
+.hextra-footer > .hextra-max-footer-width:not(.hextra-custom-footer) {
+ justify-content: center !important;
+}
+.hextra-footer > .hextra-max-footer-width:not(.hextra-custom-footer) > div {
+ align-items: center !important;
+}
+
+/* Generated card grids — top-align content */
+.section-cards .section-card {
+ justify-content: flex-start !important;
+}
+.section-cards .section-card > .hx\:mt-auto {
+ margin-top: 0 !important;
+}
+
+/* {{< cards >}} shortcode — responsive grid */
+.section-cards {
+ display: grid;
+ gap: 1rem;
+ margin-top: 1rem;
+ grid-template-columns: 1fr;
+}
+
+@media (min-width: 640px) {
+ .section-cards {
+ grid-template-columns: repeat(2, 1fr);
+ }
+}
+
+@media (min-width: 1024px) {
+ .section-cards {
+ grid-template-columns: repeat(var(--section-cards-cols, 3), minmax(0, 1fr));
+ }
+}
+
+
+
+/* Spacing between headings and following content. Needed because reuse
+ shortcode output has no wrapper, so there's no margin-top from
+ the next element. Using padding-bottom avoids doubling up with
+ margin collapsing when a proper
does follow. */
+/* Space between headings and following content. Needed because reuse
+ shortcode output often has no
wrapper, leaving bare text/links
+ with no margin-top to create a gap after the heading. */
+.content :is(h1, h2, h3, h4, h5, h6) {
+ margin-bottom: 0.75rem !important;
+}
+
+/* Space between text and code blocks inside list items and after bare text */
+.content li > .hextra-code-block,
+.content li > pre {
+ margin-top: 0.75rem;
+}
+
+/* Sidebar child indent border - dark mode */
+.dark .sidebar-container ul[style*="border-left"] {
+ border-left-color: #374151 !important;
+}
+
+
+
+/* ── Print styles ─────────────────────────────────────────────────────── */
+@media print {
+ @page { margin: 1.5cm 2cm; }
+
+ /* Hide UI chrome — sidebar/TOC already have hx:print:hidden from hextra */
+ .copy-md-wrapper,
+ .navbar,
+ .desktop-navbar,
+ .mobile-nav-bar,
+ .mobile-nav,
+ .hextra-nav-container,
+ footer,
+ .hextra-component-issue,
+ [class*="pager"],
+ [class*="page-feedback"],
+ [class*="last-updated"],
+ [class*="comments"],
+ #chatbot-widget { display: none !important; }
+
+ /* Let article fill the printable area */
+ body, html { overflow: visible !important; }
+ article {
+ display: block !important;
+ width: 100% !important;
+ max-width: 100% !important;
+ padding-right: 0 !important;
+ min-height: 0 !important;
+ }
+ article > main {
+ max-width: 100% !important;
+ padding-left: 0 !important;
+ padding-right: 0 !important;
+ }
+
+ /* Fix the main cause: code blocks clip at the paper edge on screen overflow */
+ pre, code {
+ white-space: pre-wrap !important;
+ overflow: visible !important;
+ word-break: break-word !important;
+ max-width: 100% !important;
+ }
+
+ /* Chroma lntable: the general pre/code rules above collapse the line-number
+ column at page breaks, causing two-digit numbers to split across lines.
+ Undo word-break and max-width constraints for that column only. */
+ .lntable { width: 100%; }
+ .lntable .lntd:first-child pre,
+ .lntable .lntd:first-child code {
+ white-space: pre !important;
+ word-break: normal !important;
+ overflow-wrap: normal !important;
+ max-width: none !important;
+ min-width: 2.5em;
+ }
+
+ /* Avoid breaking inside short blocks; don't force headings to next page */
+ blockquote, figure, img { break-inside: avoid; }
+}
+
+
+/* ── Top-nav dropdown popover (Docs → kagent/kmcp) ─────────────────────
+ The Docs menu item has child entries, so Hextra renders it as a dropdown
+ whose popover is