From 9e9ecc10c4d973323052f4b8f3e02c0829be7416 Mon Sep 17 00:00:00 2001 From: bordumb Date: Fri, 17 Jul 2026 20:18:37 +0100 Subject: [PATCH 1/4] =?UTF-8?q?docs:=20the=20revamp=20foundation=20?= =?UTF-8?q?=E2=80=94=20React=20Markdoc,=20one=20route,=20frontmatter=20nav?= =?UTF-8?q?,=20the=20ledger?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The four architectural debts are paid: content renders through Markdoc.renderers.react with a real tag schema (callout, cards, steps, synced code-tabs, verdict chips β€” zero dangerouslySetInnerHTML for content); every page is served by one [...slug] catch-all with metadata from frontmatter; the nav derives from a validated frontmatter contract (product/section/order/lastReviewed) so it cannot drift from disk; and the URL-keyed CodeExamples rail, the hand-written page files, and the hand-maintained nav array are gone. Design language is the marketing ledger tuned for reading β€” paper/ink/ seal tokens with a dark variant, terminal-framed code panes with copy buttons and verdict-colored transcript lines, Lucide icons (no emoji), system typeface kept. Identity content is demoted under its own product switch; the illustrative-only mcp-setup page is deleted ahead of the real auths-mcp docs. Auths-Id: did:keri:EB5cPHY0t-ejNC_rUzPS1dclTvd6kG-R9mQzjozCuGgd Auths-Device: did:keri:EB5cPHY0t-ejNC_rUzPS1dclTvd6kG-R9mQzjozCuGgd Auths-Anchor-Seq: 1 --- app/docs/[...slug]/page.tsx | 76 ++++ app/docs/authentication/page.tsx | 27 -- app/docs/build-agents/page.tsx | 24 -- app/docs/concepts/[topic]/page.tsx | 49 --- app/docs/installation/page.tsx | 24 -- app/docs/layout.tsx | 44 +-- app/docs/mcp-setup/page.tsx | 27 -- app/docs/page.tsx | 70 +--- app/docs/prove-provenance/page.tsx | 24 -- app/docs/quickstart/page.tsx | 27 -- app/docs/reference/[topic]/page.tsx | 49 --- app/docs/sign-commits/page.tsx | 34 -- app/docs/team-identities/page.tsx | 24 -- app/globals.css | 176 +++++++-- app/layout.tsx | 33 +- app/page.tsx | 151 +------- bun.lock | 3 + components/CodeBlock.tsx | 26 -- components/docs/CodeExamples.tsx | 153 -------- components/docs/DocWrapper.tsx | 17 - components/docs/DocsLayout.tsx | 1 - components/docs/DocsMobileDrawer.tsx | 52 +-- components/docs/DocsPrevNext.tsx | 35 +- components/docs/DocsSidebar.tsx | 94 +++-- components/docs/DocsTopBar.tsx | 70 ++-- components/docs/OnThisPage.tsx | 4 +- components/docs/ThemeToggle.tsx | 38 ++ components/markdoc/Callout.tsx | 92 +++-- components/markdoc/Cards.tsx | 63 +++ components/markdoc/CodeBlock.tsx | 134 +++++++ components/markdoc/CodeFence.tsx | 12 - components/markdoc/CodeTabs.tsx | 115 ++++++ components/markdoc/Steps.tsx | 23 ++ components/markdoc/VerdictChip.tsx | 22 ++ components/markdoc/language-context.tsx | 49 +++ content/docs/authentication.md | 4 + content/docs/build-agents.md | 4 + content/docs/concepts/delegation.md | 5 + content/docs/concepts/identity-model.md | 5 + content/docs/concepts/key-rotation.md | 5 + content/docs/installation.md | 4 + content/docs/mcp-setup.md | 103 ----- content/docs/prove-provenance.md | 4 + content/docs/quickstart.md | 5 + content/docs/reference/cli.md | 5 + content/docs/reference/github-actions.md | 5 + content/docs/sign-commits.md | 4 + content/docs/team-identities.md | 4 + docs/prompts/build.md | 473 +++++++++++++++++++++++ lib/content.ts | 183 +++++++++ lib/docs-navigation.ts | 114 ------ lib/markdoc-components.tsx | 26 ++ lib/markdoc.ts | 77 ++-- lib/toc-context.tsx | 46 --- markdoc/schema.ts | 120 ++++++ package.json | 1 + 56 files changed, 1778 insertions(+), 1281 deletions(-) create mode 100644 app/docs/[...slug]/page.tsx delete mode 100644 app/docs/authentication/page.tsx delete mode 100644 app/docs/build-agents/page.tsx delete mode 100644 app/docs/concepts/[topic]/page.tsx delete mode 100644 app/docs/installation/page.tsx delete mode 100644 app/docs/mcp-setup/page.tsx delete mode 100644 app/docs/prove-provenance/page.tsx delete mode 100644 app/docs/quickstart/page.tsx delete mode 100644 app/docs/reference/[topic]/page.tsx delete mode 100644 app/docs/sign-commits/page.tsx delete mode 100644 app/docs/team-identities/page.tsx delete mode 100644 components/CodeBlock.tsx delete mode 100644 components/docs/CodeExamples.tsx delete mode 100644 components/docs/DocWrapper.tsx delete mode 100644 components/docs/DocsLayout.tsx create mode 100644 components/docs/ThemeToggle.tsx create mode 100644 components/markdoc/Cards.tsx create mode 100644 components/markdoc/CodeBlock.tsx delete mode 100644 components/markdoc/CodeFence.tsx create mode 100644 components/markdoc/CodeTabs.tsx create mode 100644 components/markdoc/Steps.tsx create mode 100644 components/markdoc/VerdictChip.tsx create mode 100644 components/markdoc/language-context.tsx delete mode 100644 content/docs/mcp-setup.md create mode 100644 docs/prompts/build.md create mode 100644 lib/content.ts delete mode 100644 lib/docs-navigation.ts create mode 100644 lib/markdoc-components.tsx delete mode 100644 lib/toc-context.tsx create mode 100644 markdoc/schema.ts diff --git a/app/docs/[...slug]/page.tsx b/app/docs/[...slug]/page.tsx new file mode 100644 index 0000000..cb2c695 --- /dev/null +++ b/app/docs/[...slug]/page.tsx @@ -0,0 +1,76 @@ +import fs from 'fs' +import path from 'path' +import type { Metadata } from 'next' +import { notFound } from 'next/navigation' +import { getAllDocs, getDocBySlug, getPrevNext } from '@/lib/content' +import { parseDoc } from '@/lib/markdoc' +import { renderDoc } from '@/lib/markdoc-components' +import { DocsPrevNext } from '@/components/docs/DocsPrevNext' + +/** + * The one route for every doc page: content is data (`content/docs/**.md`), + * metadata comes from frontmatter, and the nav can never drift from disk. + */ + +type Props = { params: Promise<{ slug: string[] }> } + +export function generateStaticParams() { + return getAllDocs().map((d) => ({ slug: d.slug })) +} + +export async function generateMetadata({ params }: Props): Promise { + const { slug } = await params + const doc = getDocBySlug(slug) + if (!doc) return { title: 'Not found' } + return { + title: `${doc.frontmatter.title} β€” Auths docs`, + description: doc.frontmatter.description, + } +} + +export default async function DocPage({ params }: Props) { + const { slug } = await params + const doc = getDocBySlug(slug) + if (!doc) notFound() + + const source = fs.readFileSync(doc.filePath, 'utf8') + const { content } = parseDoc(source) + const { prev, next } = getPrevNext(doc.href) + + const editUrl = `https://github.com/auths-dev/auths-docs/edit/main/${path + .relative(process.cwd(), doc.filePath) + .split(path.sep) + .join('/')}` + + return ( +
+
+

+ {doc.frontmatter.section} +

+

+ {doc.frontmatter.title} +

+

{doc.frontmatter.description}

+
+ + {renderDoc(content)} + + + + +
+ ) +} diff --git a/app/docs/authentication/page.tsx b/app/docs/authentication/page.tsx deleted file mode 100644 index 6018faa..0000000 --- a/app/docs/authentication/page.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import fs from 'fs' -import path from 'path' -import { parseDoc } from '@/lib/markdoc' -import { DocsPrevNext } from '@/components/docs/DocsPrevNext' - -export default async function Page() { - const source = fs.readFileSync(path.join(process.cwd(), 'content/docs/authentication.md'), 'utf8') - const { html, frontmatter } = parseDoc(source) - - return ( -
-
-

{frontmatter.title}

-

{frontmatter.description}

-
-
- -
- ) -} - -export function generateMetadata() { - return { - title: 'Authentication - Auths Docs', - description: 'Authenticate your API requests with Auths API keys', - } -} diff --git a/app/docs/build-agents/page.tsx b/app/docs/build-agents/page.tsx deleted file mode 100644 index 06f6be0..0000000 --- a/app/docs/build-agents/page.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import fs from 'fs' -import path from 'path' -import { parseDoc } from '@/lib/markdoc' -import { DocsPrevNext } from '@/components/docs/DocsPrevNext' - -export default async function Page() { - const source = fs.readFileSync(path.join(process.cwd(), 'content/docs/build-agents.md'), 'utf8') - const { html, frontmatter } = parseDoc(source) - - return ( -
-
-

{frontmatter.title}

-

{frontmatter.description}

-
-
- -
- ) -} - -export function generateMetadata() { - return { title: 'Build Agents - Auths Docs', description: 'Automate code signing with agents in your CI/CD pipeline' } -} diff --git a/app/docs/concepts/[topic]/page.tsx b/app/docs/concepts/[topic]/page.tsx deleted file mode 100644 index 68f6d52..0000000 --- a/app/docs/concepts/[topic]/page.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import fs from 'fs' -import path from 'path' -import { parseDoc } from '@/lib/markdoc' -import { DocsPrevNext } from '@/components/docs/DocsPrevNext' - -interface PageProps { - params: Promise<{ topic: string }> -} - -export default async function Page(props: PageProps) { - const { topic } = await props.params - const filePath = path.join(process.cwd(), `content/docs/concepts/${topic}.md`) - - if (!fs.existsSync(filePath)) { - return
Page not found
- } - - const source = fs.readFileSync(filePath, 'utf8') - const { html, frontmatter } = parseDoc(source) - - return ( -
-
-

{frontmatter.title}

-

{frontmatter.description}

-
-
- -
- ) -} - -export async function generateStaticParams() { - const dir = path.join(process.cwd(), 'content/docs/concepts') - if (!fs.existsSync(dir)) return [] - return fs - .readdirSync(dir) - .filter((f) => f.endsWith('.md')) - .map((f) => ({ topic: f.replace(/\.md$/, '') })) -} - -export async function generateMetadata(props: PageProps) { - const { topic } = await props.params - const filePath = path.join(process.cwd(), `content/docs/concepts/${topic}.md`) - if (!fs.existsSync(filePath)) return {} - const source = fs.readFileSync(filePath, 'utf8') - const { frontmatter } = parseDoc(source) - return { title: `${frontmatter.title} - Auths Docs`, description: frontmatter.description } -} diff --git a/app/docs/installation/page.tsx b/app/docs/installation/page.tsx deleted file mode 100644 index 7952bfc..0000000 --- a/app/docs/installation/page.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import fs from 'fs' -import path from 'path' -import { parseDoc } from '@/lib/markdoc' -import { DocsPrevNext } from '@/components/docs/DocsPrevNext' - -export default async function Page() { - const source = fs.readFileSync(path.join(process.cwd(), 'content/docs/installation.md'), 'utf8') - const { html, frontmatter } = parseDoc(source) - - return ( -
-
-

{frontmatter.title}

-

{frontmatter.description}

-
-
- -
- ) -} - -export function generateMetadata() { - return { title: 'Installation - Auths Docs', description: 'Get the Auths CLI up and running' } -} diff --git a/app/docs/layout.tsx b/app/docs/layout.tsx index 398458a..b2b4a26 100644 --- a/app/docs/layout.tsx +++ b/app/docs/layout.tsx @@ -1,39 +1,31 @@ import { DocsTopBar } from '@/components/docs/DocsTopBar' import { DocsSidebar } from '@/components/docs/DocsSidebar' -import { CodeExamples } from '@/components/docs/CodeExamples' import { DocsMobileDrawer } from '@/components/docs/DocsMobileDrawer' +import { OnThisPage } from '@/components/docs/OnThisPage' +import { LanguageProvider } from '@/components/markdoc/language-context' +import { getNavigation } from '@/lib/content' + +export default function DocsLayout({ children }: { children: React.ReactNode }) { + const nav = getNavigation() -export default function DocsLayout({ - children, -}: { - children: React.ReactNode -}) { return ( - <> + -
-
-
- {/* Left Sidebar */} - +
+
+ - {/* Main Content */} -
- {children} -
+
{children}
- {/* Right Sidebar (Code Examples) */} - -
+
- {/* Mobile drawer */} - - + + ) } diff --git a/app/docs/mcp-setup/page.tsx b/app/docs/mcp-setup/page.tsx deleted file mode 100644 index 9e8f2c2..0000000 --- a/app/docs/mcp-setup/page.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import fs from 'fs' -import path from 'path' -import { parseDoc } from '@/lib/markdoc' -import { DocsPrevNext } from '@/components/docs/DocsPrevNext' - -export default async function Page() { - const source = fs.readFileSync(path.join(process.cwd(), 'content/docs/mcp-setup.md'), 'utf8') - const { html, frontmatter } = parseDoc(source) - - return ( -
-
-

{frontmatter.title}

-

{frontmatter.description}

-
-
- -
- ) -} - -export function generateMetadata() { - return { - title: 'MCP Setup - Auths Docs', - description: 'Give a Claude or Cursor agent a scoped, expiring, revocable Auths passport', - } -} diff --git a/app/docs/page.tsx b/app/docs/page.tsx index b3ffef9..8422fb5 100644 --- a/app/docs/page.tsx +++ b/app/docs/page.tsx @@ -1,68 +1,6 @@ -import Link from 'next/link' +import { redirect } from 'next/navigation' -export default function DocsPage() { - return ( -
-
-

Documentation

-

- Learn how to use Auths to sign commits, manage identities, and prove code provenance. -

-
- -
- -
πŸ“
-

- Sign Commits -

-

- Get started with cryptographic commit signing. Learn the basics and best practices. -

- - - -
πŸ‘₯
-

- Team Identities -

-

- Manage multiple identities for your team. Organize and verify contributor keys. -

- - - -
πŸ€–
-

- Build Agents -

-

- Automate code signing with agents. Integrate signing into your CI/CD pipeline. -

- - - -
πŸ”—
-

- Prove Provenance -

-

- Verify the origin of code. Prove that commits are authentic and traceable. -

- -
-
- ) +/** The docs land on the product that leads: the bounded agent. */ +export default function DocsIndex() { + redirect('/docs/mcp') } diff --git a/app/docs/prove-provenance/page.tsx b/app/docs/prove-provenance/page.tsx deleted file mode 100644 index 0df2b8e..0000000 --- a/app/docs/prove-provenance/page.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import fs from 'fs' -import path from 'path' -import { parseDoc } from '@/lib/markdoc' -import { DocsPrevNext } from '@/components/docs/DocsPrevNext' - -export default async function Page() { - const source = fs.readFileSync(path.join(process.cwd(), 'content/docs/prove-provenance.md'), 'utf8') - const { html, frontmatter } = parseDoc(source) - - return ( -
-
-

{frontmatter.title}

-

{frontmatter.description}

-
-
- -
- ) -} - -export function generateMetadata() { - return { title: 'Prove Provenance - Auths Docs', description: 'Verify the authenticity and origin of code commits' } -} diff --git a/app/docs/quickstart/page.tsx b/app/docs/quickstart/page.tsx deleted file mode 100644 index 2bdc57e..0000000 --- a/app/docs/quickstart/page.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import fs from 'fs' -import path from 'path' -import { parseDoc } from '@/lib/markdoc' -import { DocsPrevNext } from '@/components/docs/DocsPrevNext' - -export default async function Page() { - const source = fs.readFileSync(path.join(process.cwd(), 'content/docs/quickstart.md'), 'utf8') - const { html, frontmatter } = parseDoc(source) - - return ( -
-
-

{frontmatter.title}

-

{frontmatter.description}

-
-
- -
- ) -} - -export function generateMetadata() { - return { - title: 'Quickstart - Auths Docs', - description: 'Install Auths, create an identity, and verify your first signed commit in five minutes', - } -} diff --git a/app/docs/reference/[topic]/page.tsx b/app/docs/reference/[topic]/page.tsx deleted file mode 100644 index b7c01b2..0000000 --- a/app/docs/reference/[topic]/page.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import fs from 'fs' -import path from 'path' -import { parseDoc } from '@/lib/markdoc' -import { DocsPrevNext } from '@/components/docs/DocsPrevNext' - -interface PageProps { - params: Promise<{ topic: string }> -} - -export default async function Page(props: PageProps) { - const { topic } = await props.params - const filePath = path.join(process.cwd(), `content/docs/reference/${topic}.md`) - - if (!fs.existsSync(filePath)) { - return
Page not found
- } - - const source = fs.readFileSync(filePath, 'utf8') - const { html, frontmatter } = parseDoc(source) - - return ( -
-
-

{frontmatter.title}

-

{frontmatter.description}

-
-
- -
- ) -} - -export async function generateStaticParams() { - const dir = path.join(process.cwd(), 'content/docs/reference') - if (!fs.existsSync(dir)) return [] - return fs - .readdirSync(dir) - .filter((f) => f.endsWith('.md')) - .map((f) => ({ topic: f.replace(/\.md$/, '') })) -} - -export async function generateMetadata(props: PageProps) { - const { topic } = await props.params - const filePath = path.join(process.cwd(), `content/docs/reference/${topic}.md`) - if (!fs.existsSync(filePath)) return {} - const source = fs.readFileSync(filePath, 'utf8') - const { frontmatter } = parseDoc(source) - return { title: `${frontmatter.title} - Auths Docs`, description: frontmatter.description } -} diff --git a/app/docs/sign-commits/page.tsx b/app/docs/sign-commits/page.tsx deleted file mode 100644 index 7cc1f32..0000000 --- a/app/docs/sign-commits/page.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import fs from 'fs' -import path from 'path' -import { parseDoc } from '@/lib/markdoc' -import { DocsPrevNext } from '@/components/docs/DocsPrevNext' - -export default async function Page() { - const source = fs.readFileSync( - path.join(process.cwd(), 'content/docs/sign-commits.md'), - 'utf8' - ) - const { html, frontmatter } = parseDoc(source) - - return ( -
-
-

- {frontmatter.title as string} -

-

- {frontmatter.description as string} -

-
-
- -
- ) -} - -export function generateMetadata() { - return { - title: 'Sign Commits - Auths Docs', - description: 'Learn how to cryptographically sign your commits with Auths', - } -} diff --git a/app/docs/team-identities/page.tsx b/app/docs/team-identities/page.tsx deleted file mode 100644 index d55fbf9..0000000 --- a/app/docs/team-identities/page.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import fs from 'fs' -import path from 'path' -import { parseDoc } from '@/lib/markdoc' -import { DocsPrevNext } from '@/components/docs/DocsPrevNext' - -export default async function Page() { - const source = fs.readFileSync(path.join(process.cwd(), 'content/docs/team-identities.md'), 'utf8') - const { html, frontmatter } = parseDoc(source) - - return ( -
-
-

{frontmatter.title}

-

{frontmatter.description}

-
-
- -
- ) -} - -export function generateMetadata() { - return { title: 'Team Identities - Auths Docs', description: 'Manage multiple identities and signing keys for your team' } -} diff --git a/app/globals.css b/app/globals.css index 7806d96..c59e6a6 100644 --- a/app/globals.css +++ b/app/globals.css @@ -1,42 +1,110 @@ @import "tailwindcss"; +/* --------------------------------------------------------------------------- + * The ledger, for reading: the marketing site's paper-and-ink palette tuned + * for long-form docs. One accent (the seal); the reserved red means exactly + * one thing β€” a denial. Terminals and code panes are the only dark objects + * in light mode. Typeface: the system stack (unchanged). + * ------------------------------------------------------------------------ */ + +:root { + --paper: #f6f3ec; + --paper-deep: #ece7db; + --ink: #1c1814; + --ink-soft: #5b5448; + --ink-faint: #726c5e; + --rule: rgba(28, 24, 20, 0.16); + --seal: #c2401b; + --seal-deep: #9c3214; + --deny: #c0442e; + --terminal: #15130f; +} + +.dark { + --paper: #141210; + --paper-deep: #1d1a16; + --ink: #eae5db; + --ink-soft: #b3aa9b; + --ink-faint: #948b7c; + --rule: rgba(234, 229, 219, 0.14); + --seal: #e8845c; + --seal-deep: #f09b78; + --deny: #e2664a; + --terminal: #100e0b; +} + +@theme inline { + --color-paper: var(--paper); + --color-paper-deep: var(--paper-deep); + --color-ink: var(--ink); + --color-ink-soft: var(--ink-soft); + --color-ink-faint: var(--ink-faint); + --color-rule: var(--rule); + --color-seal: var(--seal); + --color-seal-deep: var(--seal-deep); + --color-deny: var(--deny); + --color-terminal: var(--terminal); +} + html { scroll-behavior: smooth; + scroll-padding-top: 5rem; +} + +body { + background: var(--paper); + color: var(--ink); } -/* Prose typography */ +/* --------------------------------------------------------------------------- + * Prose β€” one comfortable measure, generous rhythm, hairline rules. + * Code fences render through the CodeBlock component, not prose styles. + * ------------------------------------------------------------------------ */ + article.prose { - color: theme(colors.gray.900); - line-height: 1.75; + color: var(--ink-soft); + line-height: 1.7; + font-size: 1rem; } .prose h2 { - margin-top: 2rem; + margin-top: 3rem; margin-bottom: 1rem; - font-size: 1.875rem; + padding-top: 1.25rem; + border-top: 1px solid var(--rule); + font-size: 1.5rem; font-weight: 700; + letter-spacing: -0.015em; + color: var(--ink); + scroll-margin-top: 6rem; } .prose h3 { - margin-top: 1.5rem; + margin-top: 2rem; margin-bottom: 0.75rem; - font-size: 1.25rem; + font-size: 1.125rem; font-weight: 600; + color: var(--ink); + scroll-margin-top: 6rem; } .prose p { margin-bottom: 1rem; } +.prose strong { + color: var(--ink); + font-weight: 600; +} + .prose ul, .prose ol { margin-bottom: 1rem; - margin-left: 1.5rem; - padding-left: 1rem; + padding-left: 1.5rem; } .prose li { - margin-bottom: 0.5rem; + margin-bottom: 0.4rem; } .prose ul li { @@ -47,50 +115,84 @@ article.prose { list-style-type: decimal; } -/* Code blocks */ -.prose pre { - background-color: #1f2937; - color: #f3f4f6; - padding: 1rem; - border-radius: 0.5rem; - overflow-x: auto; - margin-bottom: 1rem; -} - -.prose pre code { - background-color: transparent; - color: inherit; - padding: 0; - font-size: 0.875rem; - line-height: 1.5; +.prose li::marker { + color: var(--ink-faint); } -/* Inline code */ +/* Inline code β€” an ink chip, never a color of its own. */ .prose :not(pre) > code { - background-color: #f3f4f6; - color: #dc2626; + background: color-mix(in srgb, var(--ink) 6%, transparent); + color: var(--ink); padding: 0.125rem 0.375rem; border-radius: 0.25rem; - font-family: ui-monospace, monospace; + font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.875em; - font-weight: 600; + font-weight: 500; } -/* Links */ .prose a { - color: #2563eb; + color: var(--seal); text-decoration: none; + border-bottom: 1px solid color-mix(in srgb, var(--seal) 40%, transparent); + transition: border-color 150ms ease; } .prose a:hover { - text-decoration: underline; + border-bottom-color: var(--seal); +} + +.prose a:has(code) { + border-bottom: none; } -/* Blockquotes */ .prose blockquote { - border-left: 4px solid #e5e7eb; + border-left: 2px solid color-mix(in srgb, var(--seal) 50%, transparent); padding-left: 1rem; font-style: italic; - color: #6b7280; + color: var(--ink); margin: 1.5rem 0; } + +/* Tables β€” hairlines, mono heads, no zebra. */ +.prose table { + width: 100%; + margin: 1.5rem 0; + border-collapse: collapse; + font-size: 0.9rem; +} + +.prose thead th { + text-align: left; + font-family: ui-monospace, SFMono-Regular, Menlo, monospace; + font-size: 0.72rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.08em; + color: var(--ink-faint); + border-bottom: 1px solid var(--rule); + padding: 0.5rem 0.75rem 0.5rem 0; +} + +.prose tbody td { + border-bottom: 1px solid var(--rule); + padding: 0.6rem 0.75rem 0.6rem 0; + vertical-align: top; +} + +.prose tbody tr:last-child td { + border-bottom: none; +} + +.prose hr { + border: none; + border-top: 1px solid var(--rule); + margin: 2.5rem 0; +} + +/* Anchored headings: hover reveals a link affordance. */ +.prose h2:hover::after, +.prose h3:hover::after { + content: " #"; + color: var(--ink-faint); + font-weight: 400; +} diff --git a/app/layout.tsx b/app/layout.tsx index 3c8ca43..36eeff3 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,21 +1,32 @@ import type { Metadata } from 'next' import './globals.css' +const SEAL_FAVICON = + 'data:image/svg+xml,' + export const metadata: Metadata = { - title: 'Auths Docs', - description: 'Documentation for Auths - proof of provenance for code.', - icons: { - icon: 'data:image/svg+xml,πŸ”', - }, + title: 'Auths docs', + description: + 'Bound an AI agent to a scope, a budget, and an expiry β€” and prove it with receipts anyone can verify.', + icons: { icon: SEAL_FAVICON }, } -export default function RootLayout({ - children, -}: { - children: React.ReactNode -}) { +/** Applies the stored (or system) theme before paint β€” no flash. */ +const THEME_SCRIPT = ` +try { + var t = localStorage.getItem('auths.docs.theme'); + if (t === 'dark' || (!t && window.matchMedia('(prefers-color-scheme: dark)').matches)) { + document.documentElement.classList.add('dark'); + } +} catch (e) {} +` + +export default function RootLayout({ children }: { children: React.ReactNode }) { return ( - + + +