+ );
+}
diff --git a/src/theme/DocItem/Footer/index.js b/src/theme/DocItem/Footer/index.js
new file mode 100644
index 00000000000000..1d6dbdc28070b1
--- /dev/null
+++ b/src/theme/DocItem/Footer/index.js
@@ -0,0 +1,61 @@
+/**
+ * Swizzled (ejected) from @docusaurus/theme-classic.
+ *
+ * Replaces the single "Comment on this page" link with a compact toolbar of
+ * icon buttons (copy link, comment, and an "Ask AI" menu). The tags row and the
+ * "last updated" info are preserved from the original component.
+ */
+import React from 'react';
+import clsx from 'clsx';
+import {ThemeClassNames} from '@docusaurus/theme-common';
+import {useDoc} from '@docusaurus/plugin-content-docs/client';
+import TagsListInline from '@theme/TagsListInline';
+import LastUpdated from '@theme/LastUpdated';
+import PageActions from './PageActions';
+
+export default function DocItemFooter() {
+ const {metadata} = useDoc();
+ const {editUrl, lastUpdatedAt, lastUpdatedBy, tags, source} = metadata;
+
+ const canDisplayTagsRow = tags.length > 0;
+ const canDisplayLastUpdated = !!(lastUpdatedAt || lastUpdatedBy);
+ const canDisplayFooter = canDisplayTagsRow || canDisplayLastUpdated || !!editUrl;
+
+ if (!canDisplayFooter) {
+ return null;
+ }
+
+ return (
+
+ );
+}
diff --git a/src/theme/DocItem/Footer/pageActions.module.css b/src/theme/DocItem/Footer/pageActions.module.css
new file mode 100644
index 00000000000000..48acbc12c81915
--- /dev/null
+++ b/src/theme/DocItem/Footer/pageActions.module.css
@@ -0,0 +1,111 @@
+.actions {
+ display: flex;
+ align-items: center;
+ gap: 0.4rem;
+ flex-wrap: wrap;
+}
+
+/* Breakpoint matches Infima's desktop breakpoint (997px). */
+
+/* Footer toolbar: visible on mobile/tablet, hidden on desktop (moves up top). */
+.placementFooter {
+ display: flex;
+}
+
+/* Floating toolbar: hidden on mobile, top-right by the title on desktop. */
+.placementFloating {
+ display: none;
+}
+
+@media (min-width: 997px) {
+ .placementFooter {
+ display: none;
+ }
+
+ .placementFloating {
+ display: flex;
+ position: absolute;
+ top: 48px;
+ right: 0;
+ z-index: 2;
+ }
+}
+
+/* Icon buttons (copy link, comment) */
+.action {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ gap: 0.35rem;
+ height: 2rem;
+ min-width: 2rem;
+ padding: 0 0.45rem;
+ border: 1px solid var(--ifm-color-emphasis-300);
+ border-radius: var(--ifm-global-radius);
+ background: var(--ifm-background-surface-color);
+ color: var(--ifm-font-color-base);
+ cursor: pointer;
+ transition: background var(--ifm-transition-fast),
+ border-color var(--ifm-transition-fast), color var(--ifm-transition-fast);
+}
+
+.action:hover {
+ background: var(--ifm-color-emphasis-100);
+ border-color: var(--ifm-color-primary);
+ color: var(--ifm-color-primary);
+ text-decoration: none;
+}
+
+.aiButton {
+ font-size: 0.85rem;
+ font-weight: 500;
+}
+
+.aiLabel {
+ white-space: nowrap;
+}
+
+/* Tooltip on hover/focus for icon-only buttons */
+.tooltip {
+ position: relative;
+}
+
+.tooltip::after {
+ content: attr(data-tooltip);
+ position: absolute;
+ bottom: calc(100% + 0.4rem);
+ left: 50%;
+ transform: translateX(-50%);
+ padding: 0.25rem 0.5rem;
+ border-radius: var(--ifm-global-radius);
+ background: var(--ifm-color-emphasis-800);
+ color: var(--ifm-color-emphasis-0);
+ font-size: 0.75rem;
+ line-height: 1.2;
+ white-space: nowrap;
+ opacity: 0;
+ pointer-events: none;
+ transition: opacity var(--ifm-transition-fast);
+ z-index: 5;
+}
+
+.tooltip:hover::after,
+.tooltip:focus-visible::after {
+ opacity: 1;
+}
+
+/* AI dropdown */
+.menu :global(.dropdown__menu) {
+ min-width: 12rem;
+}
+
+/* Positioning context for the floating (desktop) toolbar. */
+.floatingHost {
+ position: relative;
+}
+
+@media print {
+ .actions {
+ display: none;
+ }
+}
diff --git a/src/theme/DocItem/Layout/index.js b/src/theme/DocItem/Layout/index.js
new file mode 100644
index 00000000000000..b0a2c0fca36783
--- /dev/null
+++ b/src/theme/DocItem/Layout/index.js
@@ -0,0 +1,72 @@
+/**
+ * Swizzled (ejected) from @docusaurus/theme-classic.
+ *
+ * Adds a floating page-actions toolbar (copy link, comment, Ask AI) at the
+ * top-right of the article on desktop. On mobile the same toolbar is rendered
+ * in the footer instead (see DocItem/Footer + PageActions placement classes).
+ */
+import React from 'react';
+import clsx from 'clsx';
+import {useWindowSize} from '@docusaurus/theme-common';
+import {useDoc} from '@docusaurus/plugin-content-docs/client';
+import DocItemPaginator from '@theme/DocItem/Paginator';
+import DocVersionBanner from '@theme/DocVersionBanner';
+import DocVersionBadge from '@theme/DocVersionBadge';
+import DocItemFooter from '@theme/DocItem/Footer';
+import DocItemTOCMobile from '@theme/DocItem/TOC/Mobile';
+import DocItemTOCDesktop from '@theme/DocItem/TOC/Desktop';
+import DocItemContent from '@theme/DocItem/Content';
+import DocBreadcrumbs from '@theme/DocBreadcrumbs';
+import ContentVisibility from '@theme/ContentVisibility';
+import PageActions from '../Footer/PageActions';
+import pageActionStyles from '../Footer/pageActions.module.css';
+import styles from './styles.module.css';
+/**
+ * Decide if the toc should be rendered, on mobile or desktop viewports
+ */
+function useDocTOC() {
+ const {frontMatter, toc} = useDoc();
+ const windowSize = useWindowSize();
+ const hidden = frontMatter.hide_table_of_contents;
+ const canRender = !hidden && toc.length > 0;
+ const mobile = canRender ? : undefined;
+ const desktop =
+ canRender && (windowSize === 'desktop' || windowSize === 'ssr') ? (
+
+ ) : undefined;
+ return {
+ hidden,
+ mobile,
+ desktop,
+ };
+}
+export default function DocItemLayout({children}) {
+ const docTOC = useDocTOC();
+ const {metadata} = useDoc();
+ return (
+
+
+
+
+
+
+
+
+ {/* Absolutely positioned (top-right on desktop); DOM order is irrelevant
+ to its placement, so it stays after the breadcrumbs first-child reset. */}
+
+ {docTOC.mobile}
+ {children}
+
+
+
+