diff --git a/docs/getting-started/introduction.md b/docs/getting-started/introduction.md
deleted file mode 100644
index 77a4c5b..0000000
--- a/docs/getting-started/introduction.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-title: Introduction
----
-
-PHP Debugger is a modern debugging extension for PHP that focuses exclusively on step debugging functionality. It leaves out profiling, coverage, and tracing entirely to achieve near-zero overhead when debugging is not active. This makes it ideal for development environments where you want debugging capabilities without impacting performance during regular development work.
-
-## Key Features
-
-Everything you need for a great debugging experience:
-
-- **[Breakpoints](../user-guide/breakpoints.md)** — set breakpoints anywhere in your code with conditional support.
-- **[Step Debugging](../user-guide/step-debugging.md)** — step over, into, and out of code with ease.
-- **[Variable Inspection](../user-guide/inspect-variables.md)** — inspect variables, objects, arrays, and their properties.
-- **[Watch Expressions](../user-guide/watch-expressions.md)** — watch expressions and get notified when they change.
-- **[CLI & Remote](../advanced/remote-debugging.md)** — debug CLI scripts and remote applications.
-- **[Logging](../user-guide/logging.md)** — powerful logging capabilities for debugging and tracing.
-
-## What's Next?
-
-Ready to get started? Install PHP Debugger and try the quick start guide:
-
-- [Installation Guide](./installation.md)
-- [Quick Start](./quick-start.md)
diff --git a/docs/getting-started/introduction.mdx b/docs/getting-started/introduction.mdx
new file mode 100644
index 0000000..1f48a3d
--- /dev/null
+++ b/docs/getting-started/introduction.mdx
@@ -0,0 +1,19 @@
+---
+title: Introduction
+---
+
+import BenefitGrid from '@site/src/components/BenefitGrid';
+
+[PHP Debugger](https://github.com/php-debugger/php-debugger) is a step debugger for PHP, and nothing else. Every other feature that
+normally ships alongside one — the profiler, the coverage collector, the tracer — has
+been left out. What remains is a debugger you can leave switched on permanently,
+because when you are not using it you can barely tell it is there.
+
+
+
+## What's Next?
+
+Ready to get started? Install PHP Debugger and try the quick start guide:
+
+- [Installation Guide](./installation.md)
+- [Quick Start](./quick-start.md)
diff --git a/src/components/BenefitGrid/index.js b/src/components/BenefitGrid/index.js
new file mode 100644
index 0000000..e957da3
--- /dev/null
+++ b/src/components/BenefitGrid/index.js
@@ -0,0 +1,115 @@
+import styles from './styles.module.css';
+
+const iconProps = {
+ width: 26,
+ height: 26,
+ viewBox: '0 0 24 24',
+ fill: 'none',
+ stroke: 'currentColor',
+ strokeWidth: 1.8,
+ strokeLinecap: 'round',
+ strokeLinejoin: 'round',
+};
+
+const benefits = [
+ {
+ title: 'Near-zero overhead when idle',
+ text: 'With no debug client connected, the debugger stays out of the way. A typical web request does around 1% more work than running with no debugger at all.',
+ icon: (
+
+ ),
+ },
+ {
+ title: 'Cheap while you are attached',
+ text: 'Keep your IDE connected all day. A session you are attached to but not actively stepping through still costs very little.',
+ icon: (
+
+ ),
+ },
+ {
+ title: 'Drop-in compatible',
+ text: 'Existing INI settings, IDE configurations, and helper functions keep working. In most projects there is almost nothing to migrate — just the line that loads the extension.',
+ icon: (
+
+ ),
+ },
+ {
+ title: 'Works with your editor',
+ text: 'Full DBGp protocol support means any IDE or tool that speaks it just works — PhpStorm, VS Code, Neovim, and anything else in your setup.',
+ icon: (
+
+ ),
+ },
+ {
+ title: 'Everything you expect',
+ text: 'Breakpoints and conditional breakpoints. Step over, into, and out. Inspect variables, objects, and arrays, and watch expressions change as you go.',
+ icon: (
+
+ ),
+ },
+ {
+ title: 'One job, done well',
+ text: 'No profiler, no code coverage, no tracing. Step debugging is the only thing here, which is exactly why the rest of the time it costs you so little.',
+ icon: (
+
+ ),
+ },
+ {
+ title: 'Nothing to install',
+ text: 'Use it as a regular extension, or reach for a container image with the debugger compiled straight into the interpreter. Change one line of your Dockerfile and you are done.',
+ icon: (
+
+ ),
+ },
+ {
+ title: 'Ready the moment you are',
+ text: 'However you install it, debugging is on by default and starts with every request. Set a breakpoint, hit your app, and the session is already there — no trigger to remember.',
+ icon: (
+
+ ),
+ },
+];
+
+export default function BenefitGrid() {
+ return (
+
{keyFeatures.map((feature) => (
diff --git a/src/css/custom.css b/src/css/custom.css
index 8a70ed4..ed1fa02 100644
--- a/src/css/custom.css
+++ b/src/css/custom.css
@@ -149,3 +149,10 @@ article a {
.breadcrumbs__link {
font-size: 0.8rem;
}
+
+/* Anchor that src/theme/DocItem/Content puts on the page title, so the "on this
+ page" title entry has something to link to. Docusaurus only gives its own
+ headings the offset that clears the sticky navbar, so set it here too. */
+#page-top {
+ scroll-margin-top: calc(var(--ifm-navbar-height) + 1rem);
+}
diff --git a/src/theme/DocItem/Content/index.js b/src/theme/DocItem/Content/index.js
new file mode 100644
index 0000000..0fa85cb
--- /dev/null
+++ b/src/theme/DocItem/Content/index.js
@@ -0,0 +1,38 @@
+import clsx from 'clsx';
+import {ThemeClassNames} from '@docusaurus/theme-common';
+import {useDoc} from '@docusaurus/plugin-content-docs/client';
+import Heading from '@theme/Heading';
+import MDXContent from '@theme/MDXContent';
+
+/* Ejected from @docusaurus/theme-classic so the synthetic page title can carry
+ an anchor. The table of contents is built from h2/h3 headings only, so the
+ title is never in it; without an id here there is nothing for the "on this
+ page" entry to link to. src/theme/TOC prepends that entry and targets this id. */
+export const PAGE_TOP_ID = 'page-top';
+
+/* Docusaurus renders a "synthetic title" from front matter only when the page
+ has not asked to hide it and the content does not already open with its own
+ h1. src/theme/TOC repeats this test, so keep the two in step. */
+function useSyntheticTitle() {
+ const {metadata, frontMatter, contentTitle} = useDoc();
+ const shouldRender =
+ !frontMatter.hide_title && typeof contentTitle === 'undefined';
+ if (!shouldRender) {
+ return null;
+ }
+ return metadata.title;
+}
+
+export default function DocItemContent({children}) {
+ const syntheticTitle = useSyntheticTitle();
+ return (
+
+ );
+}
diff --git a/src/theme/TOCItems/Tree/index.js b/src/theme/TOCItems/Tree/index.js
new file mode 100644
index 0000000..ee5615d
--- /dev/null
+++ b/src/theme/TOCItems/Tree/index.js
@@ -0,0 +1,71 @@
+import React from 'react';
+import Link from '@docusaurus/Link';
+import {useDoc} from '@docusaurus/plugin-content-docs/client';
+import {PAGE_TOP_ID} from '@theme/DocItem/Content';
+
+/* Ejected from @docusaurus/theme-classic to put the page title at the top of
+ the table of contents. Docusaurus builds the list from h2/h3 headings alone,
+ so the title -- rendered as a synthetic h1 from front matter -- never appears.
+
+ Ejected rather than wrapped because the component recurses into itself, so a
+ wrapper cannot reach inside the list it renders. Both the desktop sidebar and
+ the mobile "on this page" dropdown render through here, so they stay in step. */
+
+/* Docusaurus only renders a synthetic title when the page has not hidden it and
+ the content does not already open with its own h1. src/theme/DocItem/Content
+ makes the same test before adding the anchor; keep the two in step. */
+function useSyntheticTitle() {
+ const {metadata, frontMatter, contentTitle} = useDoc();
+ if (frontMatter.hide_title || typeof contentTitle !== 'undefined') {
+ return null;
+ }
+ return metadata.title;
+}
+
+/* A plain , not a Docusaurus , on purpose. The build-time broken-anchor
+ checker inspects only, and derives the valid anchors from the page's
+ headings -- it cannot see an id added by a theme component, so a here
+ reports a broken anchor on every page that has a title. */
+function PageTitleItem({linkClassName}) {
+ const title = useSyntheticTitle();
+ if (!title) {
+ return null;
+ }
+ return (
+