{"owner":"ethereum","repo":"ethereum-org-website","hasSkills":true,"hasMcp":false,"mcpConfig":null,"found":["AGENTS.md"],"skills":{"AGENTS.md":"# CLAUDE.md - Ethereum.org Website\n\n## Project Overview\n\nThis is the official Ethereum.org website - a Next.js application that serves as the primary educational and community hub for Ethereum. The site is built with modern web technologies and focuses on accessibility, internationalization, and performance.\n\n## Technology Stack\n\n### Core Framework\n\n- **Next.js 16+** - React framework with App Router (Turbopack is the default bundler; webpack available via `pnpm dev:webpack` / `pnpm build:webpack`)\n- **React 19** - UI library\n- **TypeScript 5.5+** - Type safety and development experience\n- **Tailwind CSS 4+** - Utility-first CSS framework (CSS-first config in `src/styles/global.css`)\n\n### Key Dependencies\n\n- **next-intl 4+** - Internationalization (i18n) with 25 languages\n- **next-mdx-remote 5.0+** - MDX content processing\n- **Motion 12+** (`motion` package, formerly Framer Motion) - Animations and transitions; import from `motion/react`\n- **Radix UI** - Accessible component primitives\n- **shadcn/ui** - Component library built on Radix UI\n- **Recharts** - Data visualization\n- **Viem/Wagmi** - Ethereum blockchain integration\n\n### Development & Testing\n\n- **Storybook 10+** - Component development and testing\n- **Chromatic** - Visual regression testing\n- **ESLint** - Code linting with custom rules\n- **Prettier** - Code formatting\n- **Husky** - Git hooks\n- **PNPM** - Package manager\n\n## Project Structure\n\n- **app/** - Next.js App Router pages\n  - **[locale]/** - Internationalized routes\n- **src/**\n  - **components/** - React components\n    - **ui/** - Design system components\n    - **icons/** - SVG icon components\n  - **data/** - Static data and configurations\n  - **hooks/** - Custom React hooks\n  - **i18n/** - Internationalization config\n  - **intl/** - Translation files (25 languages)\n  - **layouts/** - Page layout components\n  - **lib/** - Utility functions and types\n    - **constants.ts** - App constants\n    - **types.ts** - TypeScript type definitions\n    - **utils/** - Utility functions\n  - **styles/** - Global styles and design tokens\n- **public/** - Static assets\n  - **content/** - Markdown content files\n  - **images/** - Image assets\n- **docs/** - Development documentation\n  - **solutions/** - Documented solutions to past problems, organized by category with YAML frontmatter (module, tags, problem_type)\n\n## Code Conventions\n\n### File Naming\n\n- **Components**: kebab-case (e.g., `button-group.tsx`)\n- **Utilities**: camelCase (e.g., `cn.ts`, `relativePath.ts`)\n- **Pages**: kebab-case following Next.js conventions\n- **Assets**: kebab-case (e.g., `eth-logo.png`)\n\n### TypeScript Patterns\n\n- Use `interface` for object shapes, `type` for unions/intersections\n- Prefer explicit typing over `any` (ESLint enforces `fixToUnknown`)\n- **NEVER leave unused variables or parameters** - ESLint `unused-imports/no-unused-vars` will fail the Netlify build. The only allowed unused arg pattern is a single underscore `_`. Do NOT use `_prefixedNames` (e.g., `_foo`) - either use the variable or remove it from the signature entirely.\n- Use generic constraints for reusable components\n- Export types from dedicated files in `@/lib/types`\n\n### Styling Conventions\n\n- **Primary approach**: Tailwind CSS utility classes\n- **Component variants**: Use `tailwind-variants` (`tv`) for new and refactored work. Existing `class-variance-authority` (`cva`) components don't need bulk migration -- swap to `tv` opportunistically when you're already touching the component for another reason.\n- **Dynamic classes**: Use `cn()` utility (clsx + tailwind-merge)\n- **Custom properties**: CSS variables in `src/styles/` for theme values\n- **Responsive design**: Mobile-first approach\n\nFor UI work, see the **`design-system` skill** at `.claude/skills/design-system/`. It's the canonical knowledge base for component choices, design tokens, RTL/i18n, server/client boundaries, and the \"use a variant, not a new component\" pattern.\n\n## Development Workflows\n\n### Available Scripts\n\n```bash\n# Development\npnpm dev                    # Start development server (Turbopack)\npnpm dev:webpack            # Start development server with webpack\npnpm build                  # Build for production (Turbopack)\npnpm build:webpack          # Build for production with webpack\npnpm start                  # Start production server\n\n# Code Quality\npnpm lint                   # Run ESLint\npnpm lint:fix              # Fix ESLint issues\npnpm type-check            # TypeScript type checking\npnpm format                # Format with Prettier\n\n# Testing\npnpm test:unit             # Playwright unit tests (unit project)\npnpm test:e2e              # Playwright end-to-end tests\npnpm test:visual           # Playwright + Chromatic full-page visual tests\n\n# Storybook\npnpm storybook             # Start Storybook dev server\npnpm build-storybook       # Build Storybook\npnpm chromatic             # Storybook Chromatic (needs CHROMATIC_STORYBOOK_TOKEN)\n\n# Content Management\npnpm lint:md               # Lint English markdown content\npnpm lint:md:fix           # Auto-fix header IDs and duplicates\n```\n\n### Testing Strategy\n\n- **Unit Testing**: Playwright `unit` project (`pnpm test:unit`) — heaviest coverage is the intl-pipeline sanitizer\n- **E2E Testing**: Playwright (`pnpm test:e2e`), see `docs/e2e-testing.md`\n- **Visual Testing**: Storybook + Chromatic for component regression; Playwright + Chromatic for full pages (see the `page-visual-tests` skill)\n- **Type Safety**: TypeScript strict mode enabled\n- **Linting**: ESLint with custom rules for imports and TypeScript\n\n## Content Management\n\n### Internationalization\n\n- **25 languages** supported (canonical list: `i18n.config.json`); **RTL support** for Arabic, Urdu\n- JSON UI strings in `src/intl/[locale]/`; translated markdown content in `public/content/translations/[locale]/`\n- Non-English markdown is propagated by the **intl-pipeline** (`src/scripts/intl-pipeline/`, entry `main.ts`). **Do not hand-propagate English changes into non-English files** -- let the pipeline run, or trigger `intl-pipeline.yml` with `stamp_only: true` if manifests must catch up urgently (e.g. unblocking a build). Hand-fixing a translation error is fine when the English side hasn't moved, since the manifest mapping stays valid. Spec: `tests/specs/PIPELINE-SPEC.md`.\n- Glossary: base URL from `GLOSSARY_API_URL` env var; default in `src/scripts/intl-pipeline/config.ts`. ETHGlossary is authoritative for Ethereum term translations.\n\nFor pipeline mechanics, recovery, manifests, ETHGlossary integration, and the `intl/pending-{base}` orchestration model, see the **`intl-pipeline` skill** at `.claude/skills/intl-pipeline/`. For translation-quality review (scoring rubric, language-group rules, ETHGlossary-as-authority policy, multi-agent role split), see the **`intl-review` skill** at `.claude/skills/intl-review/`.\n\n### Markdown Content\n\n- Educational content stored in `public/content/`\n- Processed with `next-mdx-remote`\n- Custom MDX components for rich content\n- Automatic table of contents generation\n- **All h1-h4 headings require a custom `{#lower-kebab-id}`** -- enforced by markdownlint via pre-commit hook. Run `pnpm lint:md:fix` to auto-add missing IDs. Config: `.markdownlint-cli2.jsonc`, custom rules: `.markdownlint-rules/`\n\n### Asset Management\n\n- Images optimized with Next.js Image component\n- SVGs loaded as React components via `@svgr/webpack`\n- Static assets served from `public/`\n- Placeholder generation for images\n\n## SEO & Meta\n\n- Sitemap generation in `app/sitemap.ts`\n- Meta tags and Open Graph optimization\n- Structured data for search engines\n- Security headers (X-Frame-Options: DENY)\n\n## Development Guidelines\n\n### When Working on Features\n\n1. **Check existing patterns** - Look at similar components first\n2. **Prioritize Server Components** - Use App Router and Server Components when possible\n3. **Follow import order** - ESLint will enforce, but be proactive\n4. **Use TypeScript strictly** - No `any` types, prefer `unknown`\n5. **Test in Storybook** - Create stories for new components (filename pattern: `.stories.tsx`)\n6. **Consider i18n** - All user-facing text should be translatable. Server components: `getTranslations` and `getLocale` from `next-intl/server`. Client components: `useTranslations` from `next-intl`, one namespace-bound function per namespace - to access a second namespace, bind another function (e.g. `const tCommon = useTranslations(\"common\")`) rather than reaching across namespaces\n7. **Mobile-first** - Design for mobile, enhance for desktop\n8. **Accessibility** - Use Radix primitives, semantic HTML\n9. **Use locale-aware formatting wrappers** - Use `numberFormat()` from `src/lib/utils/numbers.ts` instead of `new Intl.NumberFormat()`, and `dateTimeFormat()` from `src/lib/utils/date.ts` instead of `new Intl.DateTimeFormat()` / `.toLocaleDateString()` / `.toLocaleTimeString()`. Both enforce correct numbering systems and calendar for Urdu and Arabic locales.\n\n### Component Development\n\n1. Create component in appropriate `src/components/` subdirectory\n   - Use `src/components/ui` for shadcn components or pure UI components\n2. Add TypeScript types and proper props interface\n3. Accept `ref` as a regular prop when needed (React 19); `forwardRef` only survives in legacy components\n4. Add a Storybook story (see below)\n5. Export from appropriate index file\n6. Update documentation if adding new patterns\n\n### Storybook stories\n\n**Location**: `__stories__/` for flat directories (`ui/`, `styles/`), co-located for foldered components. Story globs are recursive, so nesting works. **Filenames are kebab-case** (`app-card.stories.tsx`) even inside a PascalCase component directory -- enforced by the test below.\n\n**Title**: `Section / Group / Name`. The section is derived from the file path -- not a judgment call:\n\n| Path                                  | Section         |\n| ------------------------------------- | --------------- |\n| `src/styles/**`                       | `Design System` |\n| `src/components/ui/**`                | `UI`            |\n| `src/components/**` (everything else) | `Components`    |\n| `src/layouts/**`                      | `Layouts`       |\n| `app/**`                              | `Pages`         |\n\nUse a second-level group only when an established one fits (Actions, Forms, Layout, Navigation, Overlays, Data Display, Cards, Heroes, Site Chrome, Content, Data Viz, Features). **Don't invent a group for a single component** -- a flat `Components / Morpher` is correct and preferred. `tests/unit/storybook/story-titles.spec.ts` enforces the section prefix, explicit titles, and title uniqueness (Storybook silently merges duplicate titles into one sidebar entry).\n\n**Don't add a story for a deprecated component or variant.** A rendered example reads as an endorsement whatever the caption says, so the showcase should only contain things that are available to use -- note the deprecation in prose instead (see `HR`). A component whose future is merely undecided can keep its story with a status blurb (see `Carousel`).\n\nAdd `tags: [\"autodocs\"]`. Write the `parameters.docs.description.component` blurb for someone deciding whether to use the thing -- constraints and gotchas, not a restatement of the props table.\n\n**A green build does not mean a story renders.** `pnpm build-storybook` compiles stories without executing them, and every `UI /` story sets `chromatic: { disableSnapshot: true }`, so neither CI signal catches a story that throws. Open new stories in `pnpm storybook` before pushing.\n\nAsync server components render via a `next-intl/server` shim (`.storybook/next-intl-server.tsx`). Components calling `usePathname` need `parameters.nextjs.navigation.pathname`. New i18n namespaces must be added to the `ns` array in `.storybook/next-intl.ts`, or strings render as raw key tails.\n\n### Content Updates\n\n1. Markdown files go in `public/content/`\n2. Images in `public/images/` with descriptive names\n3. Translation strings in appropriate `src/intl/` JSON files\n4. Data files in `src/data/` with TypeScript types\n\n### Type-Safe Chain Names\n\nThis project enforces type-safe chain names via TypeScript. When working with layer 2 networks or wallet data:\n\n**Critical Files:**\n\n- `src/data/chains.ts` - Canonical source of all chain names (auto-updated weekly)\n- `src/lib/types.ts` - Defines `ChainName` type derived from chains.ts\n- `src/data/networks/networks.ts` - Uses `chainName: ChainName`\n- `src/data/wallets/wallet-data.ts` - Uses `supported_chains: ChainName[]`\n\n**Rules:**\n\n1. **Always look up exact names** - Before adding `chainName` or `supported_chains`, search `chains.ts` for the exact `name` value\n2. **Names are case-sensitive and exact** - e.g., use `\"Zircuit Mainnet\"` not `\"Zircuit\"`, use `\"OP Mainnet\"` not `\"Optimism\"`\n3. **Run type checking** - Use `pnpm type-check` to verify chain names are valid before committing\n4. **Non-EVM chains** - For Starknet and other non-EVM chains, use `NonEVMChainName` type\n\n**Common Mistakes:**\n\n- Using informal names: `\"Optimism\"` should be `\"OP Mainnet\"`\n- Missing \"Mainnet\" suffix: `\"Zircuit\"` should be `\"Zircuit Mainnet\"`\n- Wrong casing: `\"zksync Mainnet\"` should be `\"zkSync Mainnet\"`\n\n## Key Dependencies to Know\n\n### UI & Styling\n\n- `@radix-ui/*` - Accessible component primitives\n- `tailwind-variants` - Component variant patterns\n- `motion` - Animation library (formerly framer-motion; import from `motion/react`)\n- `lucide-react` - Icon library\n\n### Content & Data\n\n- `gray-matter` - Frontmatter parsing\n- `recharts` - Data visualization\n\n### Ethereum Integration\n\n- `viem` - Ethereum library\n- `wagmi` - React hooks for Ethereum\n- `@rainbow-me/rainbowkit` - Wallet connection\n\n## A/B Testing\n\nThe site uses a GDPR-compliant, cookie-less A/B testing system built on the Flags SDK precompute pattern, integrated with Matomo. The proxy assigns variants at the edge (header fingerprinting) and rewrites to signed, statically prerendered variant pages under `ab-code/[code]/` — experiments never force dynamic rendering. Experiment status, weights, and scheduling live in the Matomo dashboard (no deploys needed). Only the default locale is tested; other locales always get the original.\n\nKey gotcha: **variants are matched by array index, not names** — the `variants` array order must match the Matomo experiment order exactly, and the `testKey` must match the Matomo experiment name exactly.\n\nFull guide (architecture, step-by-step recipe, env vars): `docs/ab-testing.md`. Code: `proxy.ts`, `src/lib/ab-testing/`, `src/components/AB/`, `app/[locale]/ab-code/`.\n\n## Deployment\n\n- **Platform**: Netlify (config in `netlify.toml`)\n- **Next.js Integration**: Uses `@netlify/plugin-nextjs` for seamless Netlify and Next.js compatibility\n- **Monitoring**: Matomo analytics integration\n\n## Internal Infrastructure\n\nThe following external-looking services are managed by the ethereum.org team:\n\n- **`s3-dcl1.ethquokkaops.io`** — S3-compatible object storage for app screenshots and media. Used by the data layer to serve images for the `/dapps` and app listing pages. Downtime here means broken images on the live site.\n- **Netlify Blobs** (`@netlify/blobs`) — Key-value store used by the data layer to cache API responses. Accessed via `src/data-layer/storage.ts`.\n"},"files":{"AGENTS.md":"# CLAUDE.md - Ethereum.org Website\n\n## Project Overview\n\nThis is the official Ethereum.org website - a Next.js application that serves as the primary educational and community hub for Ethereum. The site is built with modern web technologies and focuses on accessibility, internationalization, and performance.\n\n## Technology Stack\n\n### Core Framework\n\n- **Next.js 16+** - React framework with App Router (Turbopack is the default bundler; webpack available via `pnpm dev:webpack` / `pnpm build:webpack`)\n- **React 19** - UI library\n- **TypeScript 5.5+** - Type safety and development experience\n- **Tailwind CSS 4+** - Utility-first CSS framework (CSS-first config in `src/styles/global.css`)\n\n### Key Dependencies\n\n- **next-intl 4+** - Internationalization (i18n) with 25 languages\n- **next-mdx-remote 5.0+** - MDX content processing\n- **Motion 12+** (`motion` package, formerly Framer Motion) - Animations and transitions; import from `motion/react`\n- **Radix UI** - Accessible component primitives\n- **shadcn/ui** - Component library built on Radix UI\n- **Recharts** - Data visualization\n- **Viem/Wagmi** - Ethereum blockchain integration\n\n### Development & Testing\n\n- **Storybook 10+** - Component development and testing\n- **Chromatic** - Visual regression testing\n- **ESLint** - Code linting with custom rules\n- **Prettier** - Code formatting\n- **Husky** - Git hooks\n- **PNPM** - Package manager\n\n## Project Structure\n\n- **app/** - Next.js App Router pages\n  - **[locale]/** - Internationalized routes\n- **src/**\n  - **components/** - React components\n    - **ui/** - Design system components\n    - **icons/** - SVG icon components\n  - **data/** - Static data and configurations\n  - **hooks/** - Custom React hooks\n  - **i18n/** - Internationalization config\n  - **intl/** - Translation files (25 languages)\n  - **layouts/** - Page layout components\n  - **lib/** - Utility functions and types\n    - **constants.ts** - App constants\n    - **types.ts** - TypeScript type definitions\n    - **utils/** - Utility functions\n  - **styles/** - Global styles and design tokens\n- **public/** - Static assets\n  - **content/** - Markdown content files\n  - **images/** - Image assets\n- **docs/** - Development documentation\n  - **solutions/** - Documented solutions to past problems, organized by category with YAML frontmatter (module, tags, problem_type)\n\n## Code Conventions\n\n### File Naming\n\n- **Components**: kebab-case (e.g., `button-group.tsx`)\n- **Utilities**: camelCase (e.g., `cn.ts`, `relativePath.ts`)\n- **Pages**: kebab-case following Next.js conventions\n- **Assets**: kebab-case (e.g., `eth-logo.png`)\n\n### TypeScript Patterns\n\n- Use `interface` for object shapes, `type` for unions/intersections\n- Prefer explicit typing over `any` (ESLint enforces `fixToUnknown`)\n- **NEVER leave unused variables or parameters** - ESLint `unused-imports/no-unused-vars` will fail the Netlify build. The only allowed unused arg pattern is a single underscore `_`. Do NOT use `_prefixedNames` (e.g., `_foo`) - either use the variable or remove it from the signature entirely.\n- Use generic constraints for reusable components\n- Export types from dedicated files in `@/lib/types`\n\n### Styling Conventions\n\n- **Primary approach**: Tailwind CSS utility classes\n- **Component variants**: Use `tailwind-variants` (`tv`) for new and refactored work. Existing `class-variance-authority` (`cva`) components don't need bulk migration -- swap to `tv` opportunistically when you're already touching the component for another reason.\n- **Dynamic classes**: Use `cn()` utility (clsx + tailwind-merge)\n- **Custom properties**: CSS variables in `src/styles/` for theme values\n- **Responsive design**: Mobile-first approach\n\nFor UI work, see the **`design-system` skill** at `.claude/skills/design-system/`. It's the canonical knowledge base for component choices, design tokens, RTL/i18n, server/client boundaries, and the \"use a variant, not a new component\" pattern.\n\n## Development Workflows\n\n### Available Scripts\n\n```bash\n# Development\npnpm dev                    # Start development server (Turbopack)\npnpm dev:webpack            # Start development server with webpack\npnpm build                  # Build for production (Turbopack)\npnpm build:webpack          # Build for production with webpack\npnpm start                  # Start production server\n\n# Code Quality\npnpm lint                   # Run ESLint\npnpm lint:fix              # Fix ESLint issues\npnpm type-check            # TypeScript type checking\npnpm format                # Format with Prettier\n\n# Testing\npnpm test:unit             # Playwright unit tests (unit project)\npnpm test:e2e              # Playwright end-to-end tests\npnpm test:visual           # Playwright + Chromatic full-page visual tests\n\n# Storybook\npnpm storybook             # Start Storybook dev server\npnpm build-storybook       # Build Storybook\npnpm chromatic             # Storybook Chromatic (needs CHROMATIC_STORYBOOK_TOKEN)\n\n# Content Management\npnpm lint:md               # Lint English markdown content\npnpm lint:md:fix           # Auto-fix header IDs and duplicates\n```\n\n### Testing Strategy\n\n- **Unit Testing**: Playwright `unit` project (`pnpm test:unit`) — heaviest coverage is the intl-pipeline sanitizer\n- **E2E Testing**: Playwright (`pnpm test:e2e`), see `docs/e2e-testing.md`\n- **Visual Testing**: Storybook + Chromatic for component regression; Playwright + Chromatic for full pages (see the `page-visual-tests` skill)\n- **Type Safety**: TypeScript strict mode enabled\n- **Linting**: ESLint with custom rules for imports and TypeScript\n\n## Content Management\n\n### Internationalization\n\n- **25 languages** supported (canonical list: `i18n.config.json`); **RTL support** for Arabic, Urdu\n- JSON UI strings in `src/intl/[locale]/`; translated markdown content in `public/content/translations/[locale]/`\n- Non-English markdown is propagated by the **intl-pipeline** (`src/scripts/intl-pipeline/`, entry `main.ts`). **Do not hand-propagate English changes into non-English files** -- let the pipeline run, or trigger `intl-pipeline.yml` with `stamp_only: true` if manifests must catch up urgently (e.g. unblocking a build). Hand-fixing a translation error is fine when the English side hasn't moved, since the manifest mapping stays valid. Spec: `tests/specs/PIPELINE-SPEC.md`.\n- Glossary: base URL from `GLOSSARY_API_URL` env var; default in `src/scripts/intl-pipeline/config.ts`. ETHGlossary is authoritative for Ethereum term translations.\n\nFor pipeline mechanics, recovery, manifests, ETHGlossary integration, and the `intl/pending-{base}` orchestration model, see the **`intl-pipeline` skill** at `.claude/skills/intl-pipeline/`. For translation-quality review (scoring rubric, language-group rules, ETHGlossary-as-authority policy, multi-agent role split), see the **`intl-review` skill** at `.claude/skills/intl-review/`.\n\n### Markdown Content\n\n- Educational content stored in `public/content/`\n- Processed with `next-mdx-remote`\n- Custom MDX components for rich content\n- Automatic table of contents generation\n- **All h1-h4 headings require a custom `{#lower-kebab-id}`** -- enforced by markdownlint via pre-commit hook. Run `pnpm lint:md:fix` to auto-add missing IDs. Config: `.markdownlint-cli2.jsonc`, custom rules: `.markdownlint-rules/`\n\n### Asset Management\n\n- Images optimized with Next.js Image component\n- SVGs loaded as React components via `@svgr/webpack`\n- Static assets served from `public/`\n- Placeholder generation for images\n\n## SEO & Meta\n\n- Sitemap generation in `app/sitemap.ts`\n- Meta tags and Open Graph optimization\n- Structured data for search engines\n- Security headers (X-Frame-Options: DENY)\n\n## Development Guidelines\n\n### When Working on Features\n\n1. **Check existing patterns** - Look at similar components first\n2. **Prioritize Server Components** - Use App Router and Server Components when possible\n3. **Follow import order** - ESLint will enforce, but be proactive\n4. **Use TypeScript strictly** - No `any` types, prefer `unknown`\n5. **Test in Storybook** - Create stories for new components (filename pattern: `.stories.tsx`)\n6. **Consider i18n** - All user-facing text should be translatable. Server components: `getTranslations` and `getLocale` from `next-intl/server`. Client components: `useTranslations` from `next-intl`, one namespace-bound function per namespace - to access a second namespace, bind another function (e.g. `const tCommon = useTranslations(\"common\")`) rather than reaching across namespaces\n7. **Mobile-first** - Design for mobile, enhance for desktop\n8. **Accessibility** - Use Radix primitives, semantic HTML\n9. **Use locale-aware formatting wrappers** - Use `numberFormat()` from `src/lib/utils/numbers.ts` instead of `new Intl.NumberFormat()`, and `dateTimeFormat()` from `src/lib/utils/date.ts` instead of `new Intl.DateTimeFormat()` / `.toLocaleDateString()` / `.toLocaleTimeString()`. Both enforce correct numbering systems and calendar for Urdu and Arabic locales.\n\n### Component Development\n\n1. Create component in appropriate `src/components/` subdirectory\n   - Use `src/components/ui` for shadcn components or pure UI components\n2. Add TypeScript types and proper props interface\n3. Accept `ref` as a regular prop when needed (React 19); `forwardRef` only survives in legacy components\n4. Add a Storybook story (see below)\n5. Export from appropriate index file\n6. Update documentation if adding new patterns\n\n### Storybook stories\n\n**Location**: `__stories__/` for flat directories (`ui/`, `styles/`), co-located for foldered components. Story globs are recursive, so nesting works. **Filenames are kebab-case** (`app-card.stories.tsx`) even inside a PascalCase component directory -- enforced by the test below.\n\n**Title**: `Section / Group / Name`. The section is derived from the file path -- not a judgment call:\n\n| Path                                  | Section         |\n| ------------------------------------- | --------------- |\n| `src/styles/**`                       | `Design System` |\n| `src/components/ui/**`                | `UI`            |\n| `src/components/**` (everything else) | `Components`    |\n| `src/layouts/**`                      | `Layouts`       |\n| `app/**`                              | `Pages`         |\n\nUse a second-level group only when an established one fits (Actions, Forms, Layout, Navigation, Overlays, Data Display, Cards, Heroes, Site Chrome, Content, Data Viz, Features). **Don't invent a group for a single component** -- a flat `Components / Morpher` is correct and preferred. `tests/unit/storybook/story-titles.spec.ts` enforces the section prefix, explicit titles, and title uniqueness (Storybook silently merges duplicate titles into one sidebar entry).\n\n**Don't add a story for a deprecated component or variant.** A rendered example reads as an endorsement whatever the caption says, so the showcase should only contain things that are available to use -- note the deprecation in prose instead (see `HR`). A component whose future is merely undecided can keep its story with a status blurb (see `Carousel`).\n\nAdd `tags: [\"autodocs\"]`. Write the `parameters.docs.description.component` blurb for someone deciding whether to use the thing -- constraints and gotchas, not a restatement of the props table.\n\n**A green build does not mean a story renders.** `pnpm build-storybook` compiles stories without executing them, and every `UI /` story sets `chromatic: { disableSnapshot: true }`, so neither CI signal catches a story that throws. Open new stories in `pnpm storybook` before pushing.\n\nAsync server components render via a `next-intl/server` shim (`.storybook/next-intl-server.tsx`). Components calling `usePathname` need `parameters.nextjs.navigation.pathname`. New i18n namespaces must be added to the `ns` array in `.storybook/next-intl.ts`, or strings render as raw key tails.\n\n### Content Updates\n\n1. Markdown files go in `public/content/`\n2. Images in `public/images/` with descriptive names\n3. Translation strings in appropriate `src/intl/` JSON files\n4. Data files in `src/data/` with TypeScript types\n\n### Type-Safe Chain Names\n\nThis project enforces type-safe chain names via TypeScript. When working with layer 2 networks or wallet data:\n\n**Critical Files:**\n\n- `src/data/chains.ts` - Canonical source of all chain names (auto-updated weekly)\n- `src/lib/types.ts` - Defines `ChainName` type derived from chains.ts\n- `src/data/networks/networks.ts` - Uses `chainName: ChainName`\n- `src/data/wallets/wallet-data.ts` - Uses `supported_chains: ChainName[]`\n\n**Rules:**\n\n1. **Always look up exact names** - Before adding `chainName` or `supported_chains`, search `chains.ts` for the exact `name` value\n2. **Names are case-sensitive and exact** - e.g., use `\"Zircuit Mainnet\"` not `\"Zircuit\"`, use `\"OP Mainnet\"` not `\"Optimism\"`\n3. **Run type checking** - Use `pnpm type-check` to verify chain names are valid before committing\n4. **Non-EVM chains** - For Starknet and other non-EVM chains, use `NonEVMChainName` type\n\n**Common Mistakes:**\n\n- Using informal names: `\"Optimism\"` should be `\"OP Mainnet\"`\n- Missing \"Mainnet\" suffix: `\"Zircuit\"` should be `\"Zircuit Mainnet\"`\n- Wrong casing: `\"zksync Mainnet\"` should be `\"zkSync Mainnet\"`\n\n## Key Dependencies to Know\n\n### UI & Styling\n\n- `@radix-ui/*` - Accessible component primitives\n- `tailwind-variants` - Component variant patterns\n- `motion` - Animation library (formerly framer-motion; import from `motion/react`)\n- `lucide-react` - Icon library\n\n### Content & Data\n\n- `gray-matter` - Frontmatter parsing\n- `recharts` - Data visualization\n\n### Ethereum Integration\n\n- `viem` - Ethereum library\n- `wagmi` - React hooks for Ethereum\n- `@rainbow-me/rainbowkit` - Wallet connection\n\n## A/B Testing\n\nThe site uses a GDPR-compliant, cookie-less A/B testing system built on the Flags SDK precompute pattern, integrated with Matomo. The proxy assigns variants at the edge (header fingerprinting) and rewrites to signed, statically prerendered variant pages under `ab-code/[code]/` — experiments never force dynamic rendering. Experiment status, weights, and scheduling live in the Matomo dashboard (no deploys needed). Only the default locale is tested; other locales always get the original.\n\nKey gotcha: **variants are matched by array index, not names** — the `variants` array order must match the Matomo experiment order exactly, and the `testKey` must match the Matomo experiment name exactly.\n\nFull guide (architecture, step-by-step recipe, env vars): `docs/ab-testing.md`. Code: `proxy.ts`, `src/lib/ab-testing/`, `src/components/AB/`, `app/[locale]/ab-code/`.\n\n## Deployment\n\n- **Platform**: Netlify (config in `netlify.toml`)\n- **Next.js Integration**: Uses `@netlify/plugin-nextjs` for seamless Netlify and Next.js compatibility\n- **Monitoring**: Matomo analytics integration\n\n## Internal Infrastructure\n\nThe following external-looking services are managed by the ethereum.org team:\n\n- **`s3-dcl1.ethquokkaops.io`** — S3-compatible object storage for app screenshots and media. Used by the data layer to serve images for the `/dapps` and app listing pages. Downtime here means broken images on the live site.\n- **Netlify Blobs** (`@netlify/blobs`) — Key-value store used by the data layer to cache API responses. Accessed via `src/data-layer/storage.ts`.\n"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","title":"AGENTS.md","content":"# CLAUDE.md - Ethereum.org Website\n\n## Project Overview\n\nThis is the official Ethereum.org website - a Next.js application that serves as the primary educational and community hub for Ethereum. The site is built with modern web technologies and focuses on accessibility, internationalization, and performance.\n\n## Technology Stack\n\n### Core Framework\n\n- **Next.js 16+** - React framework with App Router (Turbopack is the default bundler; webpack available via `pnpm dev:webpack` / `pnpm build:webpack`)\n- **React 19** - UI library\n- **TypeScript 5.5+** - Type safety and development experience\n- **Tailwind CSS 4+** - Utility-first CSS framework (CSS-first config in `src/styles/global.css`)\n\n### Key Dependencies\n\n- **next-intl 4+** - Internationalization (i18n) with 25 languages\n- **next-mdx-remote 5.0+** - MDX content processing\n- **Motion 12+** (`motion` package, formerly Framer Motion) - Animations and transitions; import from `motion/react`\n- **Radix UI** - Accessible component primitives\n- **shadcn/ui** - Component library built on Radix UI\n- **Recharts** - Data visualization\n- **Viem/Wagmi** - Ethereum blockchain integration\n\n### Development & Testing\n\n- **Storybook 10+** - Component development and testing\n- **Chromatic** - Visual regression testing\n- **ESLint** - Code linting with custom rules\n- **Prettier** - Code formatting\n- **Husky** - Git hooks\n- **PNPM** - Package manager\n\n## Project Structure\n\n- **app/** - Next.js App Router pages\n  - **[locale]/** - Internationalized routes\n- **src/**\n  - **components/** - React components\n    - **ui/** - Design system components\n    - **icons/** - SVG icon components\n  - **data/** - Static data and configurations\n  - **hooks/** - Custom React hooks\n  - **i18n/** - Internationalization config\n  - **intl/** - Translation files (25 languages)\n  - **layouts/** - Page layout components\n  - **lib/** - Utility functions and types\n    - **constants.ts** - App constants\n    - **types.ts** - TypeScript type definitions\n    - **utils/** - Utility functions\n  - **styles/** - Global styles and design tokens\n- **public/** - Static assets\n  - **content/** - Markdown content files\n  - **images/** - Image assets\n- **docs/** - Development documentation\n  - **solutions/** - Documented solutions to past problems, organized by category with YAML frontmatter (module, tags, problem_type)\n\n## Code Conventions\n\n### File Naming\n\n- **Components**: kebab-case (e.g., `button-group.tsx`)\n- **Utilities**: camelCase (e.g., `cn.ts`, `relativePath.ts`)\n- **Pages**: kebab-case following Next.js conventions\n- **Assets**: kebab-case (e.g., `eth-logo.png`)\n\n### TypeScript Patterns\n\n- Use `interface` for object shapes, `type` for unions/intersections\n- Prefer explicit typing over `any` (ESLint enforces `fixToUnknown`)\n- **NEVER leave unused variables or parameters** - ESLint `unused-imports/no-unused-vars` will fail the Netlify build. The only allowed unused arg pattern is a single underscore `_`. Do NOT use `_prefixedNames` (e.g., `_foo`) - either use the variable or remove it from the signature entirely.\n- Use generic constraints for reusable components\n- Export types from dedicated files in `@/lib/types`\n\n### Styling Conventions\n\n- **Primary approach**: Tailwind CSS utility classes\n- **Component variants**: Use `tailwind-variants` (`tv`) for new and refactored work. Existing `class-variance-authority` (`cva`) components don't need bulk migration -- swap to `tv` opportunistically when you're already touching the component for another reason.\n- **Dynamic classes**: Use `cn()` utility (clsx + tailwind-merge)\n- **Custom properties**: CSS variables in `src/styles/` for theme values\n- **Responsive design**: Mobile-first approach\n\nFor UI work, see the **`design-system` skill** at `.claude/skills/design-system/`. It's the canonical knowledge base for component choices, design tokens, RTL/i18n, server/client boundaries, and the \"use a variant, not a new component\" pattern.\n\n## Development Workflows\n\n### Available Scripts\n\n```bash\n# Development\npnpm dev                    # Start development server (Turbopack)\npnpm dev:webpack            # Start development server with webpack\npnpm build                  # Build for production (Turbopack)\npnpm build:webpack          # Build for production with webpack\npnpm start                  # Start production server\n\n# Code Quality\npnpm lint                   # Run ESLint\npnpm lint:fix              # Fix ESLint issues\npnpm type-check            # TypeScript type checking\npnpm format                # Format with Prettier\n\n# Testing\npnpm test:unit             # Playwright unit tests (unit project)\npnpm test:e2e              # Playwright end-to-end tests\npnpm test:visual           # Playwright + Chromatic full-page visual tests\n\n# Storybook\npnpm storybook             # Start Storybook dev server\npnpm build-storybook       # Build Storybook\npnpm chromatic             # Storybook Chromatic (needs CHROMATIC_STORYBOOK_TOKEN)\n\n# Content Management\npnpm lint:md               # Lint English markdown content\npnpm lint:md:fix           # Auto-fix header IDs and duplicates\n```\n\n### Testing Strategy\n\n- **Unit Testing**: Playwright `unit` project (`pnpm test:unit`) — heaviest coverage is the intl-pipeline sanitizer\n- **E2E Testing**: Playwright (`pnpm test:e2e`), see `docs/e2e-testing.md`\n- **Visual Testing**: Storybook + Chromatic for component regression; Playwright + Chromatic for full pages (see the `page-visual-tests` skill)\n- **Type Safety**: TypeScript strict mode enabled\n- **Linting**: ESLint with custom rules for imports and TypeScript\n\n## Content Management\n\n### Internationalization\n\n- **25 languages** supported (canonical list: `i18n.config.json`); **RTL support** for Arabic, Urdu\n- JSON UI strings in `src/intl/[locale]/`; translated markdown content in `public/content/translations/[locale]/`\n- Non-English markdown is propagated by the **intl-pipeline** (`src/scripts/intl-pipeline/`, entry `main.ts`). **Do not hand-propagate English changes into non-English files** -- let the pipeline run, or trigger `intl-pipeline.yml` with `stamp_only: true` if manifests must catch up urgently (e.g. unblocking a build). Hand-fixing a translation error is fine when the English side hasn't moved, since the manifest mapping stays valid. Spec: `tests/specs/PIPELINE-SPEC.md`.\n- Glossary: base URL from `GLOSSARY_API_URL` env var; default in `src/scripts/intl-pipeline/config.ts`. ETHGlossary is authoritative for Ethereum term translations.\n\nFor pipeline mechanics, recovery, manifests, ETHGlossary integration, and the `intl/pending-{base}` orchestration model, see the **`intl-pipeline` skill** at `.claude/skills/intl-pipeline/`. For translation-quality review (scoring rubric, language-group rules, ETHGlossary-as-authority policy, multi-agent role split), see the **`intl-review` skill** at `.claude/skills/intl-review/`.\n\n### Markdown Content\n\n- Educational content stored in `public/content/`\n- Processed with `next-mdx-remote`\n- Custom MDX components for rich content\n- Automatic table of contents generation\n- **All h1-h4 headings require a custom `{#lower-kebab-id}`** -- enforced by markdownlint via pre-commit hook. Run `pnpm lint:md:fix` to auto-add missing IDs. Config: `.markdownlint-cli2.jsonc`, custom rules: `.markdownlint-rules/`\n\n### Asset Management\n\n- Images optimized with Next.js Image component\n- SVGs loaded as React components via `@svgr/webpack`\n- Static assets served from `public/`\n- Placeholder generation for images\n\n## SEO & Meta\n\n- Sitemap generation in `app/sitemap.ts`\n- Meta tags and Open Graph optimization\n- Structured data for search engines\n- Security headers (X-Frame-Options: DENY)\n\n## Development Guidelines\n\n### When Working on Features\n\n1. **Check existing patterns** - Look at similar components first\n2. **Prioritize Server Components** - Use App Router and Server Components when possible\n3. **Follow import order** - ESLint will enforce, but be proactive\n4. **Use TypeScript strictly** - No `any` types, prefer `unknown`\n5. **Test in Storybook** - Create stories for new components (filename pattern: `.stories.tsx`)\n6. **Consider i18n** - All user-facing text should be translatable. Server components: `getTranslations` and `getLocale` from `next-intl/server`. Client components: `useTranslations` from `next-intl`, one namespace-bound function per namespace - to access a second namespace, bind another function (e.g. `const tCommon = useTranslations(\"common\")`) rather than reaching across namespaces\n7. **Mobile-first** - Design for mobile, enhance for desktop\n8. **Accessibility** - Use Radix primitives, semantic HTML\n9. **Use locale-aware formatting wrappers** - Use `numberFormat()` from `src/lib/utils/numbers.ts` instead of `new Intl.NumberFormat()`, and `dateTimeFormat()` from `src/lib/utils/date.ts` instead of `new Intl.DateTimeFormat()` / `.toLocaleDateString()` / `.toLocaleTimeString()`. Both enforce correct numbering systems and calendar for Urdu and Arabic locales.\n\n### Component Development\n\n1. Create component in appropriate `src/components/` subdirectory\n   - Use `src/components/ui` for shadcn components or pure UI components\n2. Add TypeScript types and proper props interface\n3. Accept `ref` as a regular prop when needed (React 19); `forwardRef` only survives in legacy components\n4. Add a Storybook story (see below)\n5. Export from appropriate index file\n6. Update documentation if adding new patterns\n\n### Storybook stories\n\n**Location**: `__stories__/` for flat directories (`ui/`, `styles/`), co-located for foldered components. Story globs are recursive, so nesting works. **Filenames are kebab-case** (`app-card.stories.tsx`) even inside a PascalCase component directory -- enforced by the test below.\n\n**Title**: `Section / Group / Name`. The section is derived from the file path -- not a judgment call:\n\n| Path                                  | Section         |\n| ------------------------------------- | --------------- |\n| `src/styles/**`                       | `Design System` |\n| `src/components/ui/**`                | `UI`            |\n| `src/components/**` (everything else) | `Components`    |\n| `src/layouts/**`                      | `Layouts`       |\n| `app/**`                              | `Pages`         |\n\nUse a second-level group only when an established one fits (Actions, Forms, Layout, Navigation, Overlays, Data Display, Cards, Heroes, Site Chrome, Content, Data Viz, Features). **Don't invent a group for a single component** -- a flat `Components / Morpher` is correct and preferred. `tests/unit/storybook/story-titles.spec.ts` enforces the section prefix, explicit titles, and title uniqueness (Storybook silently merges duplicate titles into one sidebar entry).\n\n**Don't add a story for a deprecated component or variant.** A rendered example reads as an endorsement whatever the caption says, so the showcase should only contain things that are available to use -- note the deprecation in prose instead (see `HR`). A component whose future is merely undecided can keep its story with a status blurb (see `Carousel`).\n\nAdd `tags: [\"autodocs\"]`. Write the `parameters.docs.description.component` blurb for someone deciding whether to use the thing -- constraints and gotchas, not a restatement of the props table.\n\n**A green build does not mean a story renders.** `pnpm build-storybook` compiles stories without executing them, and every `UI /` story sets `chromatic: { disableSnapshot: true }`, so neither CI signal catches a story that throws. Open new stories in `pnpm storybook` before pushing.\n\nAsync server components render via a `next-intl/server` shim (`.storybook/next-intl-server.tsx`). Components calling `usePathname` need `parameters.nextjs.navigation.pathname`. New i18n namespaces must be added to the `ns` array in `.storybook/next-intl.ts`, or strings render as raw key tails.\n\n### Content Updates\n\n1. Markdown files go in `public/content/`\n2. Images in `public/images/` with descriptive names\n3. Translation strings in appropriate `src/intl/` JSON files\n4. Data files in `src/data/` with TypeScript types\n\n### Type-Safe Chain Names\n\nThis project enforces type-safe chain names via TypeScript. When working with layer 2 networks or wallet data:\n\n**Critical Files:**\n\n- `src/data/chains.ts` - Canonical source of all chain names (auto-updated weekly)\n- `src/lib/types.ts` - Defines `ChainName` type derived from chains.ts\n- `src/data/networks/networks.ts` - Uses `chainName: ChainName`\n- `src/data/wallets/wallet-data.ts` - Uses `supported_chains: ChainName[]`\n\n**Rules:**\n\n1. **Always look up exact names** - Before adding `chainName` or `supported_chains`, search `chains.ts` for the exact `name` value\n2. **Names are case-sensitive and exact** - e.g., use `\"Zircuit Mainnet\"` not `\"Zircuit\"`, use `\"OP Mainnet\"` not `\"Optimism\"`\n3. **Run type checking** - Use `pnpm type-check` to verify chain names are valid before committing\n4. **Non-EVM chains** - For Starknet and other non-EVM chains, use `NonEVMChainName` type\n\n**Common Mistakes:**\n\n- Using informal names: `\"Optimism\"` should be `\"OP Mainnet\"`\n- Missing \"Mainnet\" suffix: `\"Zircuit\"` should be `\"Zircuit Mainnet\"`\n- Wrong casing: `\"zksync Mainnet\"` should be `\"zkSync Mainnet\"`\n\n## Key Dependencies to Know\n\n### UI & Styling\n\n- `@radix-ui/*` - Accessible component primitives\n- `tailwind-variants` - Component variant patterns\n- `motion` - Animation library (formerly framer-motion; import from `motion/react`)\n- `lucide-react` - Icon library\n\n### Content & Data\n\n- `gray-matter` - Frontmatter parsing\n- `recharts` - Data visualization\n\n### Ethereum Integration\n\n- `viem` - Ethereum library\n- `wagmi` - React hooks for Ethereum\n- `@rainbow-me/rainbowkit` - Wallet connection\n\n## A/B Testing\n\nThe site uses a GDPR-compliant, cookie-less A/B testing system built on the Flags SDK precompute pattern, integrated with Matomo. The proxy assigns variants at the edge (header fingerprinting) and rewrites to signed, statically prerendered variant pages under `ab-code/[code]/` — experiments never force dynamic rendering. Experiment status, weights, and scheduling live in the Matomo dashboard (no deploys needed). Only the default locale is tested; other locales always get the original.\n\nKey gotcha: **variants are matched by array index, not names** — the `variants` array order must match the Matomo experiment order exactly, and the `testKey` must match the Matomo experiment name exactly.\n\nFull guide (architecture, step-by-step recipe, env vars): `docs/ab-testing.md`. Code: `proxy.ts`, `src/lib/ab-testing/`, `src/components/AB/`, `app/[locale]/ab-code/`.\n\n## Deployment\n\n- **Platform**: Netlify (config in `netlify.toml`)\n- **Next.js Integration**: Uses `@netlify/plugin-nextjs` for seamless Netlify and Next.js compatibility\n- **Monitoring**: Matomo analytics integration\n\n## Internal Infrastructure\n\nThe following external-looking services are managed by the ethereum.org team:\n\n- **`s3-dcl1.ethquokkaops.io`** — S3-compatible object storage for app screenshots and media. Used by the data layer to serve images for the `/dapps` and app listing pages. Downtime here means broken images on the live site.\n- **Netlify Blobs** (`@netlify/blobs`) — Key-value store used by the data layer to cache API responses. Accessed via `src/data-layer/storage.ts`.\n","category":"root","tokens":3821}]}