<!-- source-hash: 5f19dc4d30a044a74524129e66197508 -->
Thin wrapper around `next-themes` that implements the ODS design system's light/dark theme model: manual toggle only, defaulting to dark, persisted to `localStorage`, applied via `data-theme` attribute on `<html>`.

## Key Components

| Export | Type | Description |
|--------|------|-------------|
| `ThemeProvider` | Component | Pre-configured `next-themes` provider with ODS defaults; wrap the app root once |
| `useTheme` | Hook | Direct re-export of `next-themes` `useTheme`; returns full theme context |
| `useThemeToggle` | Hook | Headless convenience hook for building toggle UIs with hydration-safe mount gating |
| `THEME_STORAGE_KEY` | Constant | `"ods-theme"` — localStorage key |
| `THEME_ATTRIBUTE` | Constant | `"data-theme"` — HTML attribute toggled on `<html>` |
| `DEFAULT_THEME` | Constant | `"dark"` |

## Usage Example

**Wrap your app root (Next.js App Router):**

```typescript
// app/layout.tsx
import { ThemeProvider } from "@/components/theme-provider";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html suppressHydrationWarning>
      <body>
        <ThemeProvider>{children}</ThemeProvider>
      </body>
    </html>
  );
}
```

**Build a toggle button using `useThemeToggle`:**

```typescript
import { useThemeToggle } from "@/components/theme-provider";
import { Button } from "@ods/ui";
import { Sun01Icon, MoonIcon } from "@ods/icons";

export function ThemeToggle() {
  const { isDark, toggle, mounted } = useThemeToggle();

  return (
    <Button size="icon" variant="transparent" onClick={toggle} aria-label="Toggle theme">
      {mounted && (isDark ? <Sun01Icon /> : <MoonIcon />)}
    </Button>
  );
}
```

> **SSR note:** `mounted` is `false` during server render and flips to `true` after hydration. Gate any theme-dependent UI behind `mounted` to avoid hydration mismatches.