# gaipack — Component Catalog (Implementation Guide)

> **Source of Truth**
>
> - **This file is the source of truth for:**
>   - Each component's **import path** and **props type**
>   - **Minimal code examples**
>   - **Technology-specific prohibitions** (no raw `<a>` for CTAs, no thin wrappers, …)
>   - **Architecture** (UI Primitives / Common / Layout / Feature components / Pages)
> - **This file refers to:**
>   - Visual tokens and brand principles → `DESIGN.md`
>   - Page and section patterns (home / service detail / listings / articles …) → `PATTERNS.md`
>   - The AI working protocol (stop process, self-audit) → `AGENTS.md`
>
> **Update frequency:** High (new components, prop changes, implementation notes). Implementation details that do not change `DESIGN.md` are completed inside this file.
>
> **Stack:** Next.js App Router + React (Server Components by default) + Tailwind CSS v4 + shadcn/ui (new-york) + lucide-react. Colors, spacing, and radii come from the semantic tokens in `app/globals.css`; never override them from outside with `style` or Tailwind default colors.

---

## How to use this file (for AI)

1. **When a requirement says "implement X", first look for the component in §1–§2**
2. Once found, read **`Import` → `Props` → `minimal example`** in that order and take only what the implementation needs
3. **Variant / size / composition decisions follow each component's "Design decision" note.** Token principles for color, spacing, and typography are in `DESIGN.md`
4. **How a component sits in a page is defined in `PATTERNS.md`** (home / service detail / listing templates …)
5. If the component does not exist in this file, follow `AGENTS.md §3 Stop process`: **stop implementing and report to a human**

---

## Architecture overview

| Layer | Directory | Role | Modifiable? |
| --- | --- | --- | --- |
| **UI Primitives** | `shared/components/ui/` | shadcn/ui single-purpose components (Button, Badge, Card, Accordion) | No structural changes (tokens adjust color and spacing only) |
| **Common** | `shared/components/common/` | Site-wide shared parts (CTA, Breadcrumb, Pagination, Logo, ThemeToggle, …) | Composition changes need approval (covered in §1.5) |
| **Layout** | `shared/components/layout/` | Header / Footer rendered once by the root layout | Spec changes need approval (§2) |
| **SEO / Media** | `shared/components/seo/` / `shared/components/figma/` | JsonLd, ImageWithFallback | Same as Common |
| **Feature components** | `features/<domain>/components/` | Domain-specific composites (service detail pages, blog, news, gallery, LP, slides) | Free within the pattern in `PATTERNS.md` |
| **Pages** | `app/**/page.tsx` | Page-specific assembly | Free |

The path alias `@/` maps to the repository root. `components.json` registers shadcn with `style: new-york`, `baseColor: neutral`, `iconLibrary: lucide`.

### Live examples

The rendered look of every component is visible on https://www.gaipack.ai/ (the service detail pages show CTAs, cards, process steps, and accordions together). Use the live site to verify the behavior of a prop or variant with your own eyes.

---

## 1. UI Primitives (`shared/components/ui/`)

shadcn/ui (new-york) based. They reference the shadcn tokens (`bg-primary`, `text-muted-foreground`, …) that `app/globals.css` defines for both themes, so they need no outside styling.

### 1.1 `<Button>` — `@/shared/components/ui/button`

**Role:** A generic interactive button for in-page controls on documentation-style pages — gallery downloads and filters, media-kit downloads, service-card actions. **Marketing calls to action use `<CTA>` (§1.5.1), not `<Button>`.** The two sanctioned raw `<button>` uses in the codebase are icon-only controls with `aria-label`: the theme toggle (§1.5.5) and the header hamburger (§2.1).

**Import:**

```tsx
import { Button } from "@/shared/components/ui/button";
```

**Props:**

| prop | type | default | note |
| --- | --- | --- | --- |
| `variant` | `'default' \| 'destructive' \| 'outline' \| 'secondary' \| 'ghost' \| 'link'` | `'default'` | shadcn semantics |
| `size` | `'default' \| 'sm' \| 'lg' \| 'icon'` | `'default'` | `default` = 36px (`h-9`); `icon` is a 36px square |
| `asChild` | `boolean` | `false` | Slot-based element replacement (e.g. wrapping `Link`) |

**Minimal example:**

```tsx
<Button variant="outline" size="sm">クリア</Button>
<Button size="icon" aria-label="テーマを切り替える"><Sun /></Button>
<Button asChild><Link href="/services">一覧へ</Link></Button>
```

**Technology-specific prohibitions:**

- ❌ Raw `<button>` for anything beyond a purely structural wrapper
- ❌ Using `<Button>` for marketing CTAs (use `<CTA>`)
- ❌ Thin wrapper components (`SubmitButton`, `CloseButton` …)
- ❌ Icon-only buttons without `aria-label`

**Design decision:** When unspecified, `default`. `outline` / `ghost` for quiet auxiliary actions; `destructive` only for irreversible actions.

---

### 1.2 `<Badge>` — `@/shared/components/ui/badge`

**Role:** A compact label for status or category.

**Import:**

```tsx
import { Badge } from "@/shared/components/ui/badge";
```

**Props:**

| prop | type | default | note |
| --- | --- | --- | --- |
| `variant` | `'default' \| 'secondary' \| 'destructive' \| 'outline'` | `'default'` | |
| `asChild` | `boolean` | `false` | |

**Minimal example (feature chips inside a service card):**

```tsx
{features.slice(0, 3).map((f) => <Badge key={f} variant="secondary" className="text-xs">{f}</Badge>)}
{features.length > 3 && <Badge variant="outline" className="text-xs">+{features.length - 3}個</Badge>}
```

**Technology-specific prohibitions:**

- ❌ Conveying meaning by color alone (always include text)
- ❌ Using `<Badge>` for the accent pill tags or the How / Base / What category badges (those are `span` elements with the pill classes defined in `DESIGN.md §7.5`)

**Design decision:** `secondary` for neutral chips (service-card features, gallery tags), `outline` for counts and low-emphasis chips.

---

### 1.3 `<Card>` family — `@/shared/components/ui/card`

**Role:** A container with a border and `xl` radius for grouped content (media-kit sections, FAQ blocks).

**Import:**

```tsx
import { Card, CardHeader, CardTitle, CardDescription, CardAction, CardContent, CardFooter } from "@/shared/components/ui/card";
```

**Minimal example:**

```tsx
<Card>
  <CardHeader>
    <CardTitle>ロゴデータ</CardTitle>
    <CardDescription>公式ロゴのダウンロード</CardDescription>
  </CardHeader>
  <CardContent>…</CardContent>
</Card>
```

**Technology-specific prohibitions:**

- ❌ Wrapping listing cards or service cards in `<Card>` (they are `Link` elements with the card treatment; a `<Card>` adds a double frame)
- ❌ Overriding the radius (`rounded-xl` is applied)

**Design decision:** Use `<Card>` for content blocks inside documentation-style pages (media kit, gallery listing and detail) and for the service card grid (`ServiceCard`). Marketing cards on the home and service detail pages (problems, case studies, related services) are `Link` / `div` elements styled per `DESIGN.md §7.3`.

---

### 1.4 `<Accordion>` family — `@/shared/components/ui/accordion`

**Role:** FAQ and collapsible sections. Client component.

**Import:**

```tsx
import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from "@/shared/components/ui/accordion";
```

**Minimal example:**

```tsx
<Accordion type="single" collapsible>
  <AccordionItem value="q1">
    <AccordionTrigger>導入までの期間は？</AccordionTrigger>
    <AccordionContent>…</AccordionContent>
  </AccordionItem>
</Accordion>
```

**Technology-specific prohibitions:**

- ❌ Hand-rolled disclosure widgets with `useState` + `hidden`
- ❌ Nesting accordions

---

## 1.5 Common components (`shared/components/common/`)

Site-wide parts composed from primitives and tokens. **Color, spacing, and radius are inherited from tokens**, so component-specific color props are minimal. Adding a Common component or changing its composition needs approval; when in doubt, stop (`AGENTS.md §3`).

### 1.5.1 `<CTA>` — `@/shared/components/common/CTA`

**Role:** The marketing call to action. Implements the action hierarchy of `DESIGN.md §7.2`.

**Import:**

```tsx
import { CTA } from "@/shared/components/common/CTA";
```

**Props:**

| prop | type | default | note |
| --- | --- | --- | --- |
| `variant` | `'primary' \| 'secondary' \| 'tertiary'` | — (required) | `primary` = gradient, `secondary` = outline, `tertiary` = text link |
| `size` | `'large' \| 'compact'` | — (required) | `large` 56px / min-width 280px, `compact` 44px |
| `href` | `string` | — (required) | Renders an `<a>` |
| `children` | `ReactNode` | — (required) | Label |
| `ariaLabel` | `string` | — | Use when the label alone is ambiguous (e.g.「お問い合わせ（フォームへ移動）」) |
| `target` | `'_self' \| '_blank'` | `'_self'` | `_blank` adds `rel="noopener noreferrer"` automatically |
| `rel` | `string` | — | |
| `className` / `style` | | — | For the extra glow on hero CTAs only |

**Minimal example:**

```tsx
<CTA variant="primary" size="large" href="/contact" ariaLabel="お問い合わせ（フォームへ移動）">
  お問い合わせ
</CTA>
<CTA variant="secondary" size="compact" href="/services">サービス一覧</CTA>
```

**Technology-specific prohibitions:**

- ❌ Building a CTA from a raw `<a>` / `<button>` with gradient classes
- ❌ Two `primary` CTAs in one screen (`DESIGN.md §8.2`)
- ❌ Overriding the height or the gradient colors from outside

**Design decision:** When unspecified, `secondary` for anything that is not the screen's single primary action. The hero and the closing CTA are `primary large`; the header uses `primary compact`.

---

### 1.5.2 `<Breadcrumb>` / `<BreadcrumbWithJsonLd>` — `@/shared/components/common/Breadcrumb`

**Role:** Breadcrumb navigation. `BreadcrumbWithJsonLd` additionally emits `BreadcrumbList` structured data.

**Import:**

```tsx
import { Breadcrumb, BreadcrumbWithJsonLd } from "@/shared/components/common/Breadcrumb";
import { buildServiceBreadcrumbItems } from "@/features/services/constants/serviceCatalog";
```

**Props:**

| prop | type | note |
| --- | --- | --- |
| `items` | `BreadcrumbItem[]` — `{ name: ReactNode; href?: string; className?: string }` | The last item is the current page; items without `href` render as text |
| `className` / `separatorClassName` | `string` | |

`BreadcrumbWithJsonLd` takes `BreadcrumbTrailItem[]` — `{ name: string; path?: string; className?: string }` (plain-text `name`, root-relative `path`).

**Minimal example:**

```tsx
<Breadcrumb className="mb-4" items={buildServiceBreadcrumbItems("aidd-design")} />
<BreadcrumbWithJsonLd items={[{ name: "HOME", path: "/" }, { name: "ブログ", path: "/blog" }, { name: post.title }]} />
```

**Technology-specific prohibitions:**

- ❌ Hand-built breadcrumbs with `<ol>` / `<a>`
- ❌ Service pages that do not use `buildServiceBreadcrumbItems` (the hierarchy under `/services/aidd` must stay consistent)

---

### 1.5.3 `<Pagination>` — `@/shared/components/common/Pagination`

**Role:** Page navigation for listings.

**Props:**

| prop | type | note |
| --- | --- | --- |
| `currentPage` | `number` | 1-based |
| `totalPages` | `number` | |
| `basePath` | `string` | Page 1 URL; page 2+ becomes `${basePath}/page/${n}` |

**Minimal example:**

```tsx
<Pagination currentPage={2} totalPages={7} basePath="/blog" />
```

**Technology-specific prohibitions:**

- ❌ Hand-rolled pagination
- ❌ Query-string pagination (`?page=2`); the route is `/page/[n]`

---

### 1.5.4 `<Logo>` — `@/shared/components/common/Logo`

**Role:** The theme-aware gaipack wordmark. **The only permitted way to place the gaipack logo in UI** (`DESIGN.md §10`).

**Props:**

| prop | type | default | note |
| --- | --- | --- | --- |
| `variant` | `'default' \| 'white' \| 'black'` | `'default'` | `default` follows the theme (white on dark, black on light); `white` / `black` force one color |
| `priority` | `boolean` | `false` | `true` only for the LCP logo (Header) |
| `className` | `string` | — | |

**Minimal example:**

```tsx
<Logo priority className="w-36 md:w-42" />
<Logo variant="white" />  {/* on a fixed dark surface such as a slide */}
```

**Technology-specific prohibitions:**

- ❌ Referencing the logo image directly with `<img>` outside this component (the live preview and OG generation are the documented exceptions)
- ❌ Recoloring, redrawing, or CSS-filtering the logo

---

### 1.5.5 `<ThemeToggle>` — `@/shared/components/common/ThemeToggle`

**Role:** The sun / moon toggle between dark and light (`next-themes`). Client component. Implemented as an icon-only raw `<button>` with a Japanese `aria-label` (「ライトモードに切り替える」/「ダークモードに切り替える」) and `Sun` / `Moon` at `w-5 h-5` — one of the two sanctioned raw-button uses (§1.1).

**Props:** `className?: string`.

**Minimal example:**

```tsx
<ThemeToggle className="ml-2" />
```

**Technology-specific prohibitions:**

- ❌ A second theme toggle inside a page (the header owns it; the mobile panel reuses it)
- ❌ Reading the theme to branch colors in JSX (use tokens and `light:` classes instead)

---

### 1.5.6 `<Skeleton>` / `<HeroLoadingShell>` — `@/shared/components/common/Skeleton` / `HeroLoadingShell`

**Role:** Loading placeholders. `HeroLoadingShell` reproduces the hero + content shell of listing pages for `loading.tsx`.

**Props:**

- `<Skeleton className>` — sized by the caller to match the real content
- `<HeroLoadingShell hero={ReactNode}>{children}</HeroLoadingShell>` — `hero` receives breadcrumb and heading placeholders; `children` receives the content-area placeholders

**Minimal example:**

```tsx
<HeroLoadingShell hero={<Skeleton className="h-10 w-64" />}>
  <div className="grid md:grid-cols-3 gap-8">
    {Array.from({ length: 6 }).map((_, i) => <Skeleton key={i} className="aspect-video" />)}
  </div>
</HeroLoadingShell>
```

**Technology-specific prohibitions:**

- ❌ Spinners for page-level loading (use skeletons matching the layout)
- ❌ Skeletons that appear instantly (the 200ms delayed fade-in is built in; do not bypass it)

---

### 1.5.7 `<ErrorState>` — `@/shared/components/common/ErrorState`

**Role:** The body of `error.tsx` boundaries.

**Props:**

| prop | type | note |
| --- | --- | --- |
| `error` | `Error & { digest?: string }` | From the Next.js error boundary |
| `reset` | `() => void` | Retry callback |
| `title` / `description` | `string` | Optional copy |
| `backHref` / `backLabel` | `string` | Path back to a listing or home |
| `scope` | `string` | Console log scope |

**Minimal example:**

```tsx
"use client";
export default function BlogError(props: { error: Error & { digest?: string }; reset: () => void }) {
  return <ErrorState {...props} title="ブログを表示できませんでした" backHref="/blog" backLabel="ブログ一覧へ" scope="blog" />;
}
```

**Technology-specific prohibitions:**

- ❌ Rendering `error.message` or stack traces to the user
- ❌ Error screens without a path back

---

### 1.5.8 `<ShareButtons>` / `<RssLink>` / `<ScrollLink>` — `@/shared/components/common/…`

- `<ShareButtons url title label?>` — social share row at the end of articles. `label` defaults to「この記事をシェア」; override for news
- `<RssLink href className?>` — RSS icon link for listing heroes (`/news/feed.xml`, `/blog/feed.xml`, category feeds)
- `<ScrollLink href="#section">` — in-page anchor with smooth scrolling; keeps the plain `href` so it still works without JavaScript (`href` must start with `#`). Used on the governance LP and service pages with in-page navigation

**Technology-specific prohibitions:**

- ❌ Raw `<a href="#…">` for in-page navigation (use `ScrollLink`)
- ❌ Share buttons on non-article pages

---

### 1.5.9 `<SocialMediaSection>` — `@/shared/components/common/SocialMediaSection`

**Role:** The "Follow Us" card grid placed directly above the footer on the home page and content pages. No props.

**Minimal example:**

```tsx
<SocialMediaSection />
```

**Technology-specific prohibitions:**

- ❌ Placing social icons in the footer (they live here only)
- ❌ Adding accounts here without updating `DESIGN.md §7.4`

---

### 1.5.10 `<AskAI>` / `<LiteYouTubeEmbed>` / `<CookieConsent>` / `<OfficeOnly>`

- `<AskAI question referenceUrls className?>` — "ask an AI" launcher (used in the home page's Ask AI section). Props extend `AskAiPromptInput`
- `<LiteYouTubeEmbed videoId title className?>` — lazy YouTube embed for service heroes, the home page, recruit, LPs, case studies, and the theater page (never the raw iframe)
- `<CookieConsent />` — rendered once by the root layout inside the theme provider
- `<OfficeOnly fallback?>` — async server component that renders `children` only for requests from the provider's office network and `fallback` (default `null`) otherwise. Using it switches the page to dynamic rendering; for SSG pages use the client-side check instead

**Technology-specific prohibitions:**

- ❌ Raw `<iframe>` for YouTube
- ❌ Rendering `CookieConsent` inside a page

---

### 1.5.11 `<ImageWithFallback>` — `@/shared/components/figma/ImageWithFallback`

**Role:** `next/image` with a one-step fallback for thumbnails from the CMS or external sources. Client component.

**Props:** `ImageProps & { fallbackSrc?: string }` — on error it swaps to `fallbackSrc` (or a neutral placeholder) and skips the optimization API.

**Minimal example:**

```tsx
<ImageWithFallback src={post.thumbnail} alt={post.title} width={1200} height={675} className="w-full h-full object-cover" />
```

**Technology-specific prohibitions:**

- ❌ Raw `<img>` for CMS images (static brand visuals such as `/images/services/*.png` may use `<img>`)
- ❌ Omitting `width` / `height` (layout shift)

---

### 1.5.12 `<JsonLd>` — `@/shared/components/seo/JsonLd`

**Role:** Emits a `<script type="application/ld+json">` for structured data.

**Minimal example:**

```tsx
<JsonLd data={{ "@context": "https://schema.org", "@type": "Article", headline: post.title }} />
```

---

## 2. Layout components (`shared/components/layout/`)

### 2.1 `<Header>` — `@/shared/components/layout/Header`

**Role:** The fixed, translucent, theme-aware header with the 4px tri-color line (`DESIGN.md §7.4`). Rendered once by the root layout.

**Structure:** Logo (`<Logo className="w-[144px] md:w-[168px]" priority>`) + brand lockup (md+) → primary links (サービス一覧 / 事例紹介 / お知らせ / 採用情報 / ブログ) as `Link` with `text-content/80 hover:text-accent-purple transition-colors duration-300` → "その他" submenu (ショーケース ↗ / スライド / ギャラリー / シアター / メディアキット / FAQ) → `<ThemeToggle>` → `<CTA variant="primary" size="compact" href="/contact">`. The bar is `bg-surface/80 backdrop-blur-sm` at the top and `bg-surface/95 backdrop-blur-md` once scrolled, with a `h-[4px]` tri-color line from `lib/brand.ts`. On mobile: a hamburger (raw icon-only `<button>` with `aria-label` / `aria-expanded`) opens a panel below the header with a Home link and a「表示テーマ」row over a `bg-black/60 backdrop-blur-sm` overlay.

**Props:** `currentService: string | null` (kept for caller compatibility; unused), `currentPage?`.

**Technology-specific prohibitions:**

- ❌ Rendering `<Header>` inside a page or an LP
- ❌ Adding links without updating the navigation table in `DESIGN.md §7.4`
- ❌ Prefetching heavy routes from the header (the `/slides` link sets `prefetch={false}` deliberately)

---

### 2.2 `<Footer>` — `@/shared/components/layout/Footer`

**Role:** The five-column footer (`DESIGN.md §7.4`): four service columns grouped by category with How / Base / What badges, an「その他」column, the provider group row (text-only KDDIアイレット statement + the cloudpack logo on a white plate), metric disclaimers, and copyright. No props.

**Technology-specific prohibitions:**

- ❌ Placing the KDDI iret logo (text only, `DESIGN.md §10.3`)
- ❌ Recoloring or inverting the cloudpack logo (white plate only)
- ❌ Social icons in the footer (they live in `SocialMediaSection`)

---

## 3. Iconography mapping

Icons come from **`lucide-react`** only (the shadcn primitives depend on it). Visual rules are in `DESIGN.md §7.6`.

### Sizes by context (mandatory)

| Size | Class | Usage |
| --- | --- | --- |
| 16px | `w-4 h-4` | Inline with text, breadcrumbs, "read more" arrows |
| 20px | `w-5 h-5` | Checklist marks, list bullets |
| 24px | `w-6 h-6` | Buttons, navigation, section badges |
| 32px | `w-8 h-8` | Lead icons inside related-service cards |
| 48px | `w-12 h-12` | Problem cards, empty states, system states |

### Usage → icon table

The table lists the icons in use and the meaning each carries. Reuse the same icon for the same meaning across pages.

| Usage | lucide icon |
| --- | --- |
| Checklist item, benefit | `CheckCircle2` (plain `Check` inside compact lists) |
| Read more / next | `ArrowRight` (legacy code uses `ArrowLeft` with `rotate-180`) |
| Back | `ArrowLeft` / `ChevronLeft` |
| Pagination / carousel | `ChevronLeft` / `ChevronRight` |
| Expand / collapse | `ChevronDown` |
| Date | `Calendar` |
| Time / duration | `Clock` |
| Category / tag | `Tag` |
| External link | `ExternalLink` |
| Download (media kit, gallery) | `Download` |
| Document / requirements | `FileText` / `FileSearch` |
| Code / implementation | `Code` / `Code2` |
| Design / UI | `Palette` |
| Review / visual check | `Eye` |
| Version control / branching | `GitBranch` / `GitPullRequest` |
| Process / iteration / modernization | `RefreshCw` |
| Architecture / layers | `Layers` / `Blocks` / `Network` |
| Speed / automation | `Zap` (`ZapOff` for the opposite) |
| Security / governance | `Shield` / `ShieldCheck` / `Lock` |
| People / team / talent | `Users` / `User` / `UserCheck` / `UserSearch` |
| Organization / customer | `Building2` / `Briefcase` / `Handshake` |
| Goal / KPI | `Target` / `TrendingUp` / `BarChart3` |
| Training / learning | `GraduationCap` / `BookOpen` / `Presentation` |
| Launch / MVP | `Rocket` / `Sparkles` |
| Operations / maintenance | `Wrench` / `Settings` |
| Data / RAG | `Database` / `Package` |
| AI agent / chat | `Bot` / `MessageSquare` |
| Cost / pricing | `DollarSign` / `Coins` |
| Award / certification | `Award` |
| Video (theater) | `Play` / `Pause` / `Clapperboard` |
| Testimonial | `Quote` |
| Search | `Search` |
| Contact | `Mail` |
| Theme toggle | `Sun` / `Moon` |
| Close | `X` |
| Warning / caution | `AlertTriangle` |
| Offline / secure browser | `WifiOff` / `Globe` |
| Info / note | `Info` |
| Social (Follow Us) | `Facebook` / `Linkedin` / `Youtube` (X, Instagram, TikTok use inline official marks) |

### Icons not in the table

1. If lucide has a semantically matching icon, adopt it and add a row to the table in the same PR
2. If the concept is gaipack-specific and lucide has nothing suitable, leave it unassigned and confirm through the stop process (`AGENTS.md §3`). Never substitute a look-alike
3. Adding a custom icon requires brand-owner approval (`DESIGN.md §11`)

### Technology-specific prohibitions

- ❌ Mixing other icon libraries
- ❌ Icon-only interactive elements without `aria-label` / `sr-only`
- ❌ Arbitrary icon sizes (use the five sizes above)
- ❌ Reusing an icon with a different meaning because it "looks right"

---

## 4. Files and naming

### 4.1 Directory structure

```
app/
  globals.css                # Tailwind + semantic tokens (:root = light, .dark = dark) + light-flat rules
  layout.tsx                 # Header / Footer / CookieConsent / theme provider
  **/page.tsx                # pages (Server Components by default)
  **/loading.tsx  error.tsx  not-found.tsx
features/
  services/  blog/  news/  gallery/  columns/  faq/  lp/  slides/
    components/  api/  types/  data/  constants/
shared/components/
  ui/                        # shadcn primitives
  common/                    # CTA, Breadcrumb, Pagination, Logo, ThemeToggle, Skeleton, …
  layout/                    # Header, Footer
  seo/  figma/
lib/                         # utilities, brand constants (lib/brand.ts), CMS client, OG image
public/
  DESIGN.md  COMPONENTS.md  PATTERNS.md  AGENTS.md  CHANGELOG.md   # the design-system norms (published)
  images/                    # brand assets (see DESIGN.md §10)
```

### 4.2 Naming rules

| Target | Rule | Example |
| --- | --- | --- |
| Component files (Common / Layout / Feature) | PascalCase | `SocialMediaSection.tsx` |
| shadcn primitives | kebab-case (generated) | `accordion.tsx` |
| Component names | PascalCase, **named export** | `export function CTA()` |
| Props types | `<Component>Props` | `CTAProps` |
| Import alias | `@/` (repository root) | `@/shared/components/common/CTA` |
| Semantic token utilities | `bg-surface` / `text-content-muted` / `text-accent-cyan` | via `@theme inline` in `globals.css` |
| Scoped LP tokens | `--lp-*` / `--gov-*` / `--svc-*` | `var(--lp-border)` |

### 4.3 When to add `"use client"`

- Add it to components that use state, events, browser APIs, or `next-themes` (ThemeToggle, Accordion, ImageWithFallback, the live preview)
- Leave pure presentational components (CTA, Breadcrumb, Logo, Skeleton, Footer) as Server Components

---

## 5. Undefined UI (hallucination prevention)

**AI must not fill in UI that does not exist in this catalog (§1 / §1.5 / §2) by inventing or approximating it.** Stop implementing and confirm with a human via `AGENTS.md §3 Stop process`.

### 5.1 When to stop

- A requirement names a UI that is **not** in §1–§2
- It cannot be expressed by composing existing components either
- The component name is ambiguous (an external framework name, an ARIA role, a design-tool name) and it is unclear which gaipack component is meant
- A color or size outside the `DESIGN.md` YAML tokens is needed
- An icon is not in lucide and needs gaipack-specific artwork

### 5.2 Stop format (identical to `AGENTS.md §3`)

```
[STOP]
Reason: <UI not in COMPONENTS.md / value outside DESIGN.md tokens / not in the requirements>
Requirement location: <issue / PR / line>
Closest existing UI: <COMPONENTS.md §X.X / PATTERNS.md §Y>
Proposal: A) <substitute with existing> / B) <add new — approval required> / C) <requirement needs clarification>
```

When a name is ambiguous, present candidates with the `[NAME CHECK]` format in `AGENTS.md §3`.

### 5.3 Token exists, UI not implemented

If `DESIGN.md` defines a token (e.g. `badge-category`) but this catalog has no implementation entry, **approval is required before implementing**. Do not assume the treatment from the token alone.

### 5.4 Examples of forbidden "filling in"

- ❌ Importing a similar shadcn component that is not in this catalog to stand in
- ❌ Assembling something "close enough" from raw elements and Tailwind default colors
- ❌ "Helpfully" adding features absent from the requirements (search bars, notifications, KPI cards …) (`AGENTS.md §6`)

---

## 6. Related documents

- Visual tokens and brand principles → `DESIGN.md`
- Page and section patterns → `PATTERNS.md`
- AI working protocol (stop process, norm priority, self-audit) → `AGENTS.md`
- Change history → `CHANGELOG.md`
- Live site → https://www.gaipack.ai/
