agentleFS
Sign inSign up

melta-ui

tsubotax/melta-ui/llms-full.txt

主要ドキュメントの全文連結(scripts/design/build-llms-txt.ts で生成。直接編集しない)。 インデックス版: https://raw.githubusercontent.com/tsubotax/melta-ui/main/llms.txt ===== DESIGN.md =====

llms.txt201 starsChanged 25 days ago
# melta UI — llms-full.txt

> 主要ドキュメントの全文連結(scripts/design/build-llms-txt.ts で生成。直接編集しない)。
> インデックス版: https://raw.githubusercontent.com/tsubotax/melta-ui/main/llms.txt

===== DESIGN.md =====

---
# Generated from design/contracts/tokens.json by scripts/design/export-designmd.ts — do not edit by hand.
# Format: Google DESIGN.md spec (github.com/google-labs-code/design.md). SSOT remains design/contracts/.
version: alpha
name: melta UI
description: 声を張らずに伝わる UI — Quiet Precision / Breathable / Flat & Layered / Subtle Warmth
colors:
  primary: "#2b70ef"
  primary-50: "#f0f5ff"
  primary-100: "#dde8ff"
  primary-200: "#c0d4ff"
  primary-300: "#95b6ff"
  primary-400: "#6492ff"
  primary-500: "#2b70ef"
  primary-600: "#2250df"
  primary-700: "#1a40b5"
  primary-800: "#13318d"
  primary-900: "#0e266a"
  primary-950: "#07194e"
  body: "#3d4b5f"
  neutral: "#f9fafb"
  success: "#059669"
  warning: "#d97706"
  danger: "#dc2626"
typography:
  h1:
    fontFamily: Inter
    fontSize: 2rem
    lineHeight: 1.4
    letterSpacing: 0.01em
  h2:
    fontFamily: Inter
    fontSize: 1.625rem
    lineHeight: 1.4
    letterSpacing: 0.01em
  h3:
    fontFamily: Inter
    fontSize: 1.375rem
    lineHeight: 1.4
    letterSpacing: 0.01em
  body-lg:
    fontFamily: Inter
    fontSize: 1.25rem
    lineHeight: 1.5
    letterSpacing: 0.02em
  body:
    fontFamily: Inter
    fontSize: 1.125rem
    lineHeight: 2.0
    letterSpacing: 0.02em
  body-sm:
    fontFamily: Inter
    fontSize: 0.9375rem
    lineHeight: 1.7
    letterSpacing: 0.02em
  caption:
    fontFamily: Inter
    fontSize: 0.8125rem
    lineHeight: 1.4
    letterSpacing: 0.02em
rounded:
  sm: 0.25rem
  md: 0.5rem
  lg: 0.75rem
  full: 9999px
spacing:
  "1": 4px
  "2": 8px
  "3": 12px
  "4": 16px
  "5": 20px
  "6": 24px
  "8": 32px
  "10": 40px
  "12": 48px
  "14": 56px
  "16": 64px
components:
  accordion-single:
    rounded: "{rounded.md}"
  accordion-multiple:
    rounded: "{rounded.md}"
  alert-info:
    backgroundColor: "{colors.primary-50}"
    textColor: "{colors.primary-800}"
    rounded: "{rounded.md}"
    padding: 16px
  alert-success:
    backgroundColor: "#ecfdf5"
    textColor: "#065f46"
    rounded: "{rounded.md}"
    padding: 16px
  alert-warning:
    backgroundColor: "#fffbeb"
    textColor: "#92400e"
    rounded: "{rounded.md}"
    padding: 16px
  alert-error:
    backgroundColor: "#fef2f2"
    textColor: "#991b1b"
    rounded: "{rounded.md}"
    padding: 16px
  avatar-image:
    height: 40px
    rounded: "{rounded.full}"
  avatar-initials:
    height: 40px
    rounded: "{rounded.full}"
    backgroundColor: "{colors.primary-50}"
    textColor: "{colors.primary-600}"
  badge-neutral:
    rounded: "{rounded.full}"
    backgroundColor: "#f1f5f9"
    textColor: "#334155"
  badge-success:
    rounded: "{rounded.full}"
    backgroundColor: "#ecfdf5"
    textColor: "#047857"
  badge-warning:
    rounded: "{rounded.full}"
    backgroundColor: "#fffbeb"
    textColor: "#b45309"
  badge-danger:
    rounded: "{rounded.full}"
    backgroundColor: "#fef2f2"
    textColor: "#b91c1c"
  badge-accent:
    rounded: "{rounded.full}"
    backgroundColor: "{colors.primary-50}"
    textColor: "{colors.primary-700}"
  button-contained:
    height: 40px
    backgroundColor: "{colors.primary-500}"
    textColor: "#ffffff"
    rounded: "{rounded.md}"
  button-contained-hover:
    backgroundColor: "{colors.primary-700}"
  button-outlined:
    height: 40px
    backgroundColor: "#ffffff"
    textColor: "#334155"
    rounded: "{rounded.md}"
  button-outlined-hover:
    backgroundColor: "{colors.neutral}"
  button-brand-outline:
    height: 40px
    textColor: "{colors.primary-500}"
    backgroundColor: "#ffffff"
    rounded: "{rounded.md}"
  button-brand-outline-hover:
    backgroundColor: "{colors.primary-50}"
  button-neutral:
    height: 40px
    backgroundColor: "#f1f5f9"
    textColor: "#334155"
    rounded: "{rounded.md}"
  button-neutral-hover:
    backgroundColor: "#e2e8f0"
  button-lighted:
    height: 40px
    backgroundColor: "{colors.primary-50}"
    textColor: "{colors.primary-600}"
    rounded: "{rounded.md}"
  button-lighted-hover:
    backgroundColor: "{colors.primary-100}"
  button-danger:
    height: 40px
    backgroundColor: "{colors.danger}"
    textColor: "#ffffff"
    rounded: "{rounded.md}"
  button-danger-hover:
    backgroundColor: "#b91c1c"
  button-subtle:
    height: 40px
    textColor: "#334155"
    rounded: "{rounded.md}"
  button-subtle-hover:
    backgroundColor: "{colors.neutral}"
  card-basic:
    backgroundColor: "#ffffff"
    rounded: "{rounded.lg}"
    padding: 24px
  card-media:
    backgroundColor: "#ffffff"
    rounded: "{rounded.lg}"
  card-action:
    backgroundColor: "#ffffff"
    rounded: "{rounded.lg}"
    padding: 24px
  card-link:
    backgroundColor: "#ffffff"
    rounded: "{rounded.lg}"
    padding: 24px
  checkbox-default:
    height: 16px
  checkbox-disabled:
    height: 16px
  checkbox-indeterminate:
    height: 16px
  copy-button-outlined:
    backgroundColor: "#ffffff"
  datepicker-trigger:
    rounded: "{rounded.md}"
    backgroundColor: "#ffffff"
  datepicker-calendar:
    backgroundColor: "#ffffff"
    rounded: "{rounded.lg}"
    padding: 16px
  datepicker-day-cell:
    height: 40px
    rounded: "{rounded.md}"
  dropdown-basic:
    backgroundColor: "#ffffff"
    rounded: "{rounded.md}"
  dropdown-with-icons:
    backgroundColor: "#ffffff"
    rounded: "{rounded.md}"
  dropdown-with-separator:
    backgroundColor: "#ffffff"
    rounded: "{rounded.md}"
  list-link:
    textColor: "{colors.body}"
  list-link-hover:
    backgroundColor: "{colors.neutral}"
  list-information:
    textColor: "{colors.body}"
  list-action:
    textColor: "{colors.body}"
  list-action-hover:
    backgroundColor: "{colors.neutral}"
  pagination-active:
    height: 40px
    textColor: "#ffffff"
    backgroundColor: "{colors.primary-500}"
    rounded: "{rounded.md}"
  pagination-inactive:
    height: 40px
    textColor: "#334155"
    backgroundColor: "#ffffff"
    rounded: "{rounded.md}"
  pagination-inactive-hover:
    backgroundColor: "{colors.neutral}"
  pagination-disabled:
    height: 40px
    textColor: "#cbd5e1"
  progress-primary:
    backgroundColor: "#e2e8f0"
    rounded: "{rounded.full}"
    height: 8px
  progress-success:
    backgroundColor: "#e2e8f0"
    rounded: "{rounded.full}"
    height: 8px
  progress-indeterminate:
    backgroundColor: "#e2e8f0"
    rounded: "{rounded.full}"
    height: 8px
  select-default:
    rounded: "{rounded.md}"
  select-error:
    rounded: "{rounded.md}"
    backgroundColor: "#fef2f2"
  select-disabled:
    rounded: "{rounded.md}"
    backgroundColor: "#f1f5f9"
    textColor: "#94a3b8"
  sidebar-standard:
    backgroundColor: "#ffffff"
  sidebar-compact:
    backgroundColor: "#ffffff"
  sidebar-drawer:
    backgroundColor: "#ffffff"
  skeleton-text:
    backgroundColor: "#e2e8f0"
    rounded: 6px
    height: 16px
  skeleton-card:
    backgroundColor: "#ffffff"
    rounded: "{rounded.lg}"
    padding: 24px
  skeleton-circle:
    backgroundColor: "#e2e8f0"
    rounded: "{rounded.full}"
    height: 40px
  tabs-underline-active:
    textColor: "{colors.primary-500}"
  tabs-underline-inactive:
    textColor: "#64748b"
  tabs-bar-active:
    textColor: "#0f172a"
  tabs-bar-active-hover:
    backgroundColor: "#f1f5f9"
  tabs-bar-inactive:
    textColor: "#94a3b8"
  tabs-bar-inactive-hover:
    backgroundColor: "#f1f5f9"
  tag-basic:
    rounded: "{rounded.full}"
    backgroundColor: "#f1f5f9"
    textColor: "#334155"
  tag-removable:
    rounded: "{rounded.full}"
    backgroundColor: "#f1f5f9"
    textColor: "#334155"
  tag-filter-chip:
    rounded: "{rounded.full}"
    backgroundColor: "#ffffff"
    textColor: "#334155"
  textfield-default:
    rounded: "{rounded.md}"
  textfield-error:
    rounded: "{rounded.md}"
    backgroundColor: "#fef2f2"
  textfield-disabled:
    rounded: "{rounded.md}"
    backgroundColor: "#f1f5f9"
    textColor: "#94a3b8"
  textfield-success:
    rounded: "{rounded.md}"
  toast-success:
    backgroundColor: "#ecfdf5"
    textColor: "#065f46"
    rounded: "{rounded.md}"
    padding: 16px
  toast-error:
    backgroundColor: "#fef2f2"
    textColor: "#991b1b"
    rounded: "{rounded.md}"
    padding: 16px
  toast-warning:
    backgroundColor: "#fffbeb"
    textColor: "#92400e"
    rounded: "{rounded.md}"
    padding: 16px
  toast-info:
    backgroundColor: "{colors.primary-50}"
    textColor: "{colors.primary-800}"
    rounded: "{rounded.md}"
    padding: 16px
  toggle-off:
    height: 24px
    rounded: "{rounded.full}"
    backgroundColor: "#cbd5e1"
  toggle-on:
    height: 24px
    rounded: "{rounded.full}"
    backgroundColor: "{colors.primary-500}"
  tooltip-top:
    backgroundColor: "#475569"
    textColor: "#ffffff"
    rounded: "{rounded.md}"
  tooltip-bottom:
    backgroundColor: "#475569"
    textColor: "#ffffff"
    rounded: "{rounded.md}"
  tooltip-left:
    backgroundColor: "#475569"
    textColor: "#ffffff"
    rounded: "{rounded.md}"
  tooltip-right:
    backgroundColor: "#475569"
    textColor: "#ffffff"
    rounded: "{rounded.md}"
---

# melta UI — Design Constitution

> AI エージェントが UI を生成するとき、最初に読むファイル。
> 思想・非交渉原則・クイックリファレンス・参照先をこの 1 枚に集約する。

---

## Brand Identity

**"声を張らずに伝わる UI"** — 機能的な黒子であり、たまに微笑む。

| キーワード | 意味 |
|---|---|
| Quiet Precision | 静かだが精密。目立たないところほど丁寧に |
| Breathable | 文字・要素の周囲に空気がある |
| Flat & Layered | Background → Surface → Text の 3 層で奥行き |
| Subtle Warmth | 控えめだが冷たくない。機能性にエモーショナルな温度 |

参考: Linear / Notion / Stripe / Vercel
アンチ: ネオン SaaS、Bootstrap 的テンプレート

---

## Non-Negotiable Principles

1. **Content First** — UI は黒子。コンテンツが主役
2. **WCAG 2.1 AA** — コントラスト 4.5:1 以上。アクセシビリティはデフォルト
3. **Semantic Color** — `bg-primary-500` を使う。`bg-blue-*` は使わない
4. **3-Color Rule** — 1 画面に使う色は 3 色まで(背景・アクセント・テキスト)
5. **4px Grid** — スペーシングは 4 の倍数、8 の倍数推奨
6. **Minimal Elevation** — `shadow-sm` 〜 `shadow-md`。`shadow-lg` 以上はオーバーレイ限定
7. **No AI-ish Decoration** — カード上部/左端のカラーバー禁止。全周ボーダーで構成
8. **Baseline Widely Available** — CSS/HTML 機能は Baseline **Widely available** のみ使用。Newly / Limited(Anchor Positioning・Invoker Commands・popover 等)は fallback を併記しコメントで明示宣言した場合のみ許可(`BASELINE_*` ルールが検知)

> **disabled の規範(2026-07-19)**: `disabled` 属性には `aria-disabled="true"` を併記する(`A11Y_DISABLED_REQUIRES_ARIA` が検知)。タブ順を維持したい文脈(ツールバー・ページネーション等)では native `disabled` を使わず **`aria-disabled` 単独 + JS click ガード(preventDefault)** でフォーカス可能なまま無効を伝えてよい。ただし `aria-disabled` は click / Enter / submit を止めないため JS ガード必須、フォーム送信除外も効かない(送信除外が必要なら native `disabled` を維持する)。

> **コントラストの既知境界(意図宣言, 2026-07-03)**: `primary-500 × 白`(contained ボタン / brand-outline 文字 / pagination active)は実測 4.50:1 の AA 境界上。axe の判定(4.5 ちょうど = pass)を採用し、ブランド基準色を優先して**意図的に維持**する。より高いコントラストが必要な文脈では `primary-600` を使う(lighted 系の文字・avatar initials は 600 に引き上げ済み、danger base は `#dc2626` に引き上げ済み)。disabled 状態のコントラストは WCAG 1.4.3 の除外対象で対応不要。

---

## Quick Reference

> この section だけで基本的な UI コード生成が可能。

### HTML テンプレート(Tailwind CDN)

> プロトタイプ = この CDN テンプレ(Tailwind v3 構文)/ プロダクション = `foundations/theme.md` の v4 `@theme`。
> 値の SSOT は `design/contracts/tokens.json`(`scripts/ds-config.js` / `ds-theme.css` と同期)。
> **fontSize は 8 段すべて Tailwind デフォルトと異なる**(本文 18px / 行間 2.0 が melta の核。xxs はタブラベル等の最小ラベル専用)。省略すると DS のタイポグラフィが再現されない。

```html
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
  theme: {
    extend: {
      colors: {
        primary: {
          50:'#f0f5ff',100:'#dde8ff',200:'#c0d4ff',300:'#95b6ff',
          400:'#6492ff',500:'#2b70ef',600:'#2250df',700:'#1a40b5',
          800:'#13318d',900:'#0e266a',950:'#07194e'
        },
        body: '#3d4b5f',
        wf: { bg:'#FFFFFF', surface:'#F5F5F5', border:'#E0E0E0', text:'#333333', 'text-sub':'#888888', accent:'#666666' }
      },
      fontFamily: {
        sans: ['Inter','Hiragino Sans','Hiragino Kaku Gothic ProN','Noto Sans JP','sans-serif'],
        mono: ['JetBrains Mono','SF Mono','monospace']
      },
      fontSize: {
        xxs: ['0.625rem', { lineHeight: '1.4' }],
        xs: ['0.8125rem', { lineHeight: '1.4' }],
        sm: ['0.9375rem', { lineHeight: '1.7' }],
        base: ['1.125rem', { lineHeight: '2.0' }],
        lg: ['1.25rem', { lineHeight: '1.5' }],
        xl: ['1.375rem', { lineHeight: '1.4' }],
        '2xl': ['1.625rem', { lineHeight: '1.4' }],
        '3xl': ['2rem', { lineHeight: '1.4' }]
      }
    }
  }
}
</script>
<style>
  body { line-height: 2.0; letter-spacing: 0.02em; }
  h1, h2, h3, h4, h5, h6 { line-height: 1.4; letter-spacing: 0.01em; }
  .text-body { color: #3d4b5f; } /* colors.body と同値(旧テンプレ互換) */
</style>
```

### レイアウト

```
ページ全体         : bg-gray-50 min-h-screen
ページコンテンツ   : max-w-[1042px] mx-auto px-4(melta ショーケース実装値。1サイト内では全ページ同一幅で揃える。アプリ画面は patterns/layout.md の用途別幅でも可)
サイドバー+メイン : flex h-screen(ボーダー分離、gap不要)
セクション間隔     : mt-10 〜 mt-14
仕切り線           : border-t border-slate-200
```

### テキスト

```
見出し             : text-3xl font-bold text-slate-900(32px)
本文               : text-base text-body(18px, line-height 2.0。leading-* で上書きしない)
フォーム制御ラベル : 包含 <div> に leading-normal(body の lh 2.0 リセット)
空状態メッセージ   : text-base text-slate-500 text-center py-16
フォントスタック   : Inter, Hiragino Sans, Hiragino Kaku Gothic ProN, Noto Sans JP, sans-serif
```

### コンポーネント

```
カード             : bg-white rounded-xl border border-slate-200 p-6 shadow-sm
カードグリッド     : grid grid-cols-2 md:grid-cols-3 gap-6
CTAボタン(M)     : inline-flex items-center justify-center gap-2 h-10 px-4 text-[1rem] font-medium bg-primary-500 text-white rounded-lg hover:bg-primary-700 cursor-pointer
CTAボタン(L)     : inline-flex items-center justify-center gap-2 h-12 px-6 text-[1rem] font-medium bg-primary-500 text-white rounded-lg hover:bg-primary-700 cursor-pointer
CTAボタン(S)     : inline-flex items-center justify-center gap-1.5 h-8 px-3 text-[0.875rem] font-medium bg-primary-500 text-white rounded-lg hover:bg-primary-700 cursor-pointer
サブボタン         : inline-flex items-center justify-center gap-2 h-10 px-4 text-[1rem] font-medium bg-white text-slate-700 border border-slate-200 rounded-lg hover:bg-gray-50 cursor-pointer
Icon+Textボタン    : inline-flex items-center justify-center gap-2 h-10 pl-3 pr-4 text-[1rem] font-medium(アイコン側を狭く)
アイコンボタン(M): w-10 h-10 inline-flex items-center justify-center cursor-pointer + aria-label(icon w-5 h-5)
アイコンボタン(S): w-8 h-8 inline-flex items-center justify-center cursor-pointer + aria-label(icon w-4 h-4)
アイコンボタン(L): w-12 h-12 inline-flex items-center justify-center cursor-pointer + aria-label(icon w-5 h-5)
入力欄             : w-full px-3 py-2 text-base border border-slate-300 rounded-lg focus:ring-2 focus:ring-primary-500/50 caret-primary-500
セレクト           : appearance-none pl-3 pr-10 + relative wrapper + SVG chevron(absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4)← ネイティブ矢印は使用禁止
横並びフォーム     : flex flex-wrap items-end gap-4 + 各 div.leading-normal > label + 要素 h-11
バッジ             : bg-slate-100 text-slate-700 px-3 py-1 rounded-full text-xs font-medium
タグ(削除可能)   : inline-flex items-center gap-1 px-3 py-1 rounded-full text-xs font-medium + ×ボタン
Alert(Info)      : flex items-start gap-3 p-4 bg-primary-50 border border-primary-200 text-primary-800 rounded-lg
テーブル外枠       : bg-white rounded-xl border border-slate-200 overflow-hidden
テーブルヘッダ     : <th scope="col"> text-left py-3 px-4 text-xs font-medium text-slate-500 uppercase tracking-wider
テーブルデータ行   : hover:bg-gray-50 transition-colors
```

### ナビゲーション

```
サイドバー(標準) : w-64 bg-white border-r border-slate-200 flex-shrink-0 flex flex-col h-screen
ナビ(Active)     : flex items-center gap-3 px-4 py-2.5 text-sm font-medium text-primary-500 bg-primary-50 rounded-lg + aria-current="page"
ナビ(Default)    : flex items-center gap-3 px-4 py-2.5 text-sm font-medium text-body hover:bg-gray-50 rounded-lg transition-colors
タブ(Active)     : text-sm font-semibold text-primary-500 border-b-2 border-primary-500
パンくず           : text-sm + text-slate-500 hover:text-slate-700 / 現在ページ text-slate-900 font-medium
```

### アイコン

```
Charcoal           : w-5 h-5 fill="currentColor" text-body ← assets/icons/{Name}.svg(207個)
Lucide             : w-5 h-5 stroke="currentColor" fill="none" ← assets/icons/lucide/{name}.svg(15個)
小サイズ           : w-4 h-4
```

### ワイヤーフレーム(低忠実度プロトタイプ用)

```
背景               : bg-wf-bg (#FFFFFF)
サーフェス         : bg-wf-surface (#F5F5F5)
ボーダー           : border-wf-border (#E0E0E0)
テキスト           : text-wf-text (#333333)
サブテキスト       : text-wf-text-sub (#888888)
アクセント         : text-wf-accent / bg-wf-accent (#666666)
```

### 禁止パターン要約(Top 10)

| 禁止 | 代替 |
|------|------|
| `text-black` | `text-slate-900` |
| `bg-indigo-*` / `bg-blue-*` | `primary-*` |
| `shadow-lg` / `shadow-2xl` | `shadow-sm` 〜 `shadow-md` |
| `rounded-none` on cards | `rounded-xl` |
| `border-t-4` / `border-l-4` カラーバー | `border border-*-200 rounded-lg` 全周 |
| `text-gray-400` for body | `text-body` (#3d4b5f) |
| `font-light` | `font-normal` 以上 |
| `tracking-tight` | `tracking-normal` 以上 |
| `py-0.5` for buttons | `h-8` 以上 |
| `bg-green-*` / `bg-yellow-*` | `bg-emerald-*` / `bg-amber-*` |

> 全ルール(107 件): `design/contracts/rules.json`(machine-readable)
> 人間向け解説: `foundations/prohibited.md`

---

## Source of Truth 読み順

| # | ファイル | 役割 |
|---|---------|------|
| 1 | `DESIGN.md`(本ファイル) | 憲法 + quick ref |
| 2 | `design/authority.md` | SSOT 宣言 |
| 3 | `design/contracts/tokens.json` | トークン exact value |
| 4 | `design/contracts/rules.json` | 禁止ルール registry |
| 5 | `design/contracts/components/*.contract.json` | コンポーネント仕様 |
| 6 | `foundations/theme.md` | テーマ設定・CSS 変数 |
| 7 | `foundations/design_philosophy.md` | 哲学の詳細 |
| 8 | `components/*.md` / `patterns/*.md` | 人間向けの詳細ガイド |

---

## Agent Prompt Guide

### クイック(単体 UI 生成)

`DESIGN.md` のみ読めば OK。Quick Reference のクラスをそのまま使う。

### 標準(ページ単位)

`DESIGN.md` → `foundations/theme.md` → 関連 `components/*.md` or `*.contract.json`

### フル(新規プロジェクト / DS 変更)

全ファイルを読み順に従って読む。

### MCP

MCP ツール `get_token` / `get_component` / `check_rule` / `check_html` / `get_rules` / `search` を使用。Resource は `melta://tokens` / `melta://components` / `melta://rules`(全99件)/ `melta://rules/auto-detectable`(自動検出サブセット)。

> 生成後は `check_html` に生成コード全体を渡して自己検証する(CI / hook と同一ロジック)。violations が空でも文脈依存の manual ルールは自動検査外(応答の coverage に明記される)。

---

## Theme

| 設定 | 値 |
|------|-----|
| ダークモード | `OFF`(ライトモードのみ) |
| Primary | `#2B70EF`(WCAG AA 4.50:1) |
| Font | Inter, Hiragino Sans, Noto Sans JP |
| Icon | Charcoal 207 個 + Lucide 15 個 |
| Locale | ja(日本語) |

> 詳細: `foundations/theme.md`


===== design/authority.md =====

# Authority Table — Source of Truth 宣言

> melta UI のすべての情報について、**唯一の真実の所在(SSOT)**を定義する。
> 二重管理を防ぐため、各領域の authoring source と generated view を明確に分離する。

---

## Authoring Source(人が編集する)

| 領域 | SSOT | 形式 | 説明 |
|------|------|------|------|
| AI 向け入口・デザイン憲法 | `DESIGN.md` | Markdown | 思想・原則・quick ref・読み順 |
| Claude Code 作業手順 | `CLAUDE.md` | Markdown | この repo での作業ルール |
| デザイントークン | `design/contracts/tokens.json` | JSON | 色・spacing・typography 等の exact value |
| コンポーネント仕様 | `design/contracts/components/*.contract.json` | JSON | variant・size・a11y・rules 等の厳密仕様 |
| 禁止ルール | `design/contracts/rules.json` | JSON | ルール ID + severity + detector |
| デザイン哲学 | `foundations/design_philosophy.md` | Markdown | ブランド思想の詳細 |
| テーマ設定 | `foundations/theme.md` | Markdown | プライマリカラー・フォント・アイコン等 |

## Generated View(ビルドで生成する / 直接編集しない)

| 成果物 | 生成元 | 用途 |
|--------|--------|------|
| `metadata/components.json` | `design/contracts/components/*.contract.json` | MCP サーバー・AI ツール用の集約データ |
| MCP `melta://design-constitution` レスポンス | `DESIGN.md` | MCP だけで接続する AI の最初の入口(runtime 直読、内容の複製なし) |
| MCP `melta://rules` レスポンス | `design/contracts/rules.json` | AI エージェントからのルール参照 |
| `docs/` の component count・nav | contracts + tokens | 公開サイト表示 |
| `llms.txt` / `llms-full.txt` | contracts + DESIGN.md ほか(`build-llms-txt.ts`) | AI エージェント入口(llmstxt.org 形式)。リンク先は GitHub raw。melta.tsubotax.com は showcase 専用で配信しない |

## Human-Readable Docs(参照用。値の SSOT ではない)

| ファイル群 | 役割 | SSOT との関係 |
|-----------|------|---------------|
| `foundations/*.md`(theme.md, design_philosophy.md 除く) | 人間向けの設計ガイド | contracts/tokens の値を prose で解説 |
| `components/*.md` | 人間向けのコンポーネントガイド | contracts の仕様を prose で解説 |
| `patterns/*.md` | 組み合わせパターン | 複数 contracts を横断する指針 |
| `foundations/prohibited.md` | 禁止パターン一覧(人間向け) | `rules.json` の prose 版 |

---

## 移行ルール

1. **値を変更するときは authoring source を編集する**。generated view は `build-legacy.ts` で再生成する
2. **contracts に移行済みのコンポーネント**は `*.contract.json` が SSOT。`components/*.md` と `metadata/components.json` は参照用
3. **contracts 未移行のコンポーネント**は当面 `metadata/components.json` の既存データが SSOT
4. **禁止ルール**の SSOT は `design/contracts/rules.json`。`foundations/prohibited.md` は人間向けの説明文書
5. **drift が発生したら**、authoring source を正として generated view を再生成する
6. **deprecated compatibility path `tokens/tokens.json` は存在してはならない**。tokens の SSOT は `design/contracts/tokens.json` のみで、旧パスの復活はファイル・symlink を問わず `npm run design:check` が検出する
6. **ドキュメント間で値が競合したら**、`design/contracts/` > `DESIGN.md` Quick Reference > `patterns/` / `components/` md の順で優先する


===== foundations/theme.md =====

# Theme Configuration

> プロジェクトごとのカスタマイズはこのファイルで完結する。
> プロジェクト側に `design-system/foundations/theme.md` がある場合はそちらの値で上書きされる。

---

## Brand

- Primary color: `#2B70EF`(OKLCH再生成 — WCAG AA 4.50:1)
- Brand name: (プロジェクトで設定)

## Primary Palette

```css
--color-primary-50:  #f0f5ff;
--color-primary-100: #dde8ff;
--color-primary-200: #c0d4ff;
--color-primary-300: #95b6ff;
--color-primary-400: #6492ff;
--color-primary-500: #2b70ef;   /* ★ CTA・ボタン・アクティブ状態(hover は 700) */
--color-primary-600: #2250df;
--color-primary-700: #1a40b5;
--color-primary-800: #13318d;
--color-primary-900: #0e266a;
--color-primary-950: #07194e;
```

WCAGコントラスト比:
- 白文字 on primary-500: **4.50:1** — AA準拠
- primary-500 on 白背景: **4.50:1** — AA準拠

ダークモードでの使い分け:

| 用途 | Light | Dark | 理由 |
|------|-------|------|------|
| CTAボタン背景 | primary-500 | primary-500 | 暗い背景での視認性確保 |
| テキストリンク | primary-500 | primary-400 | 暗いsurface上でのコントラスト比確保 |
| Subtle背景 | primary-50 | primary-500/12% | 透過で暗い背景に馴染ませる |
| フォーカスリング | primary-500/50 | primary-400/50 | 同上 |

## Font Stack

```
font-sans: "Inter", "Hiragino Sans", "Hiragino Kaku Gothic ProN", "Noto Sans JP", sans-serif
font-mono: "JetBrains Mono", "SF Mono", monospace
```

## Icon Library

デュアルソース構成。Charcoal をプライマリとし、SaaS 向けの不足分を Lucide で補完する。

### プライマリ: Charcoal Icons 2.0

- Source: **Charcoal Icons 2.0**(pixiv design system)
- Format: SVGファイル(`assets/icons/{Name}.svg`)全207個
- Size: 24px統一(表示サイズはTailwindクラスで制御)
- Naming: PascalCase(例: `ArrowDown`, `OpenInNew`)
- Color: `fill="currentColor"` でテーマカラーを継承

### セカンダリ: Lucide Icons(補完用)

- Source: **Lucide Icons**(Charcoal に存在しないアイコンのみ)
- Format: SVGファイル(`assets/icons/lucide/{name}.svg`)15個
- Size: 24px viewBox(表示サイズはTailwindクラスで制御)
- Naming: kebab-case(例: `bar-chart-2`, `trending-up`)
- Color: `stroke="currentColor"` + `fill="none"` でテーマカラーを継承
- 対象: Analytics(bar-chart-2, trending-up/down, activity)、Time(clock)、Security(shield, key)、Infrastructure(cloud, database, server)、Files(folder)、Payment(credit-card)、Device(monitor)、International(globe)、Communication(phone)

> **ルール**: 同じ概念のアイコンが Charcoal にある場合は必ず Charcoal を使う。Lucide は Charcoal に明確に存在しないアイコンのみ許可。

- 詳細: `foundations/icons.md` を参照

## Tech Stack

- CSS: Tailwind CSS 4
- Component: (プロジェクトで設定 — Stimulus / React / Vue / etc.)
- Template: HTML(プロジェクトで設定 — HTML / ERB / JSX / etc.)

## Locale

- Language: ja(日本語)
- ラベル例: 保存する、キャンセル、削除する、閉じる、戻る、次へ
- 日付形式: YYYY-MM-DD
- 通貨形式: ¥1,000

## CSS変数の定義

`application.css`(または同等のエントリCSS)の `@theme` ブロックで以下を定義する:

```css
@theme {
  --color-primary-50:  #f0f5ff;
  --color-primary-100: #dde8ff;
  --color-primary-200: #c0d4ff;
  --color-primary-300: #95b6ff;
  --color-primary-400: #6492ff;
  --color-primary-500: #2b70ef;
  --color-primary-600: #2250df;
  --color-primary-700: #1a40b5;
  --color-primary-800: #13318d;
  --color-primary-900: #0e266a;
  --color-primary-950: #07194e;

  /* text-body: 本文デフォルト色(slate-600〜700の中間) */
  --color-body: #3d4b5f;

  /* セマンティックカラー変数(ダークモード対応) */
  --color-bg-page:        var(--bg-page);
  --color-bg-surface:     var(--bg-surface);
  --color-text-heading:   var(--text-heading);
  --color-text-default:   var(--text-default);
  --color-text-muted:     var(--text-muted);
  --color-border-default: var(--border-default);
}

/* ---- Light Theme (default) ---- */
:root {
  --bg-page:        #f9fafb;   /* gray-50 */
  --bg-page-alt:    #f3f4f6;   /* gray-100 */
  --bg-surface:     #ffffff;
  --bg-surface-alt: #f9fafb;   /* gray-50 */
  --text-heading:   #0f172a;   /* slate-900 */
  --text-default:   #3d4b5f;   /* body */
  --text-muted:     #64748b;   /* slate-500 */
  --border-default: #e2e8f0;   /* slate-200 */
  --border-strong:  #cbd5e1;   /* slate-300 */
  --input-bg:       #ffffff;
  --input-border:   #cbd5e1;   /* slate-300 */
  --shadow-color:   0, 0, 0;   /* black base */
  --shadow-opacity: 0.05;
}

/* ---- Dark Theme ---- */
/* 切替: prefers-color-scheme OR html[data-theme="dark"] */
@media (prefers-color-scheme: dark) {
  :root { @mixin dark-tokens; }
}
html[data-theme="dark"] { @mixin dark-tokens; }

/* dark-tokens mixin(実際のCSS実装では共通ブロックにまとめる) */
/*
  --bg-page:        #161718;
  --bg-page-alt:    #232525;
  --bg-surface:     #1b1c1d;
  --bg-surface-alt: #161718;
  --text-heading:   #eeeeee;
  --text-default:   #eeeeee;
  --text-muted:     #a3a3a3;
  --border-default: #373839;
  --border-strong:  #777777;
  --input-bg:       #161718;
  --input-border:   #777777;
  --shadow-color:   0, 0, 0;
  --shadow-opacity: 0.3;
*/
```

> `text-body` は Tailwind 4 のカスタムカラーとして `--color-body` で定義する。`text-body` クラスで自動的に適用される。
> ダークモードでは `--color-body` を `:root` の `--text-default` にバインドし、`prefers-color-scheme: dark` または `data-theme="dark"` で `#eeeeee`に切り替える。

---

## Semantic Colors

セマンティックカラーマッピング。CSS変数として `@theme` に定義し、ダークモードで値を切り替える。

> 全トークン詳細(Background / Surface / Text / Border / Focus / Input / Shadow): `foundations/color.md` 参照

## Elevation (Shadow)

| トークン | Tailwind | 用途 |
|---------|----------|------|
| elevation-none | `shadow-none` | フラット、disabled |
| elevation-sm | `shadow-sm` | カード、トースト |
| elevation-md | `shadow-md` | カード hover、ドロップダウン |
| elevation-overlay | `shadow-xl` | モーダル |

> 詳細: `foundations/elevation.md`

## Border Radius

| トークン | Tailwind | 用途 |
|---------|----------|------|
| radius-sm | `rounded` | チェックボックス |
| radius-md | `rounded-lg` | ボタン、入力欄、トースト |
| radius-lg | `rounded-xl` | カード、モーダル |
| radius-full | `rounded-full` | バッジ、トグル |

> 詳細: `foundations/radius.md`

## Motion

| トークン | 値 | 用途 |
|---------|-----|------|
| duration-fast | 150ms | ボタン hover 等 |
| duration-normal | 200ms | フェード |
| duration-slow | 300ms | トースト、複合 |

> 詳細: `foundations/motion.md`

## Z-index

| トークン | Tailwind | 用途 |
|---------|----------|------|
| z-base | `z-0` | コンテンツ |
| z-dropdown | `z-20` | ドロップダウン |
| z-sticky | `z-30` | sticky ヘッダー |
| z-overlay | `z-40` | モーダル背景 |
| z-modal | `z-50` | モーダル本体、トースト |

> 詳細: `foundations/z-index.md`


===== design/contracts/tokens.json =====

{"version":"1.0.0","color":{"primary":{"50":{"value":"#f0f5ff","tailwind":"primary-50"},"100":{"value":"#dde8ff","tailwind":"primary-100"},"200":{"value":"#c0d4ff","tailwind":"primary-200"},"300":{"value":"#95b6ff","tailwind":"primary-300"},"400":{"value":"#6492ff","tailwind":"primary-400"},"500":{"value":"#2b70ef","tailwind":"primary-500"},"600":{"value":"#2250df","tailwind":"primary-600"},"700":{"value":"#1a40b5","tailwind":"primary-700"},"800":{"value":"#13318d","tailwind":"primary-800"},"900":{"value":"#0e266a","tailwind":"primary-900"},"950":{"value":"#07194e","tailwind":"primary-950"}},"body":{"value":"#3d4b5f","tailwind":"body"},"semantic":{"light":{"bg-page":{"value":"#f9fafb","tailwind":"bg-gray-50","cssVar":"--bg-page"},"bg-page-alt":{"value":"#f3f4f6","tailwind":"bg-gray-100","cssVar":"--bg-page-alt"},"bg-surface":{"value":"#ffffff","tailwind":"bg-white","cssVar":"--bg-surface"},"bg-surface-alt":{"value":"#f9fafb","tailwind":"bg-gray-50","cssVar":"--bg-surface-alt"},"text-heading":{"value":"#0f172a","tailwind":"text-slate-900","cssVar":"--text-heading"},"text-default":{"value":"#3d4b5f","tailwind":"text-body","cssVar":"--text-default"},"text-muted":{"value":"#64748b","tailwind":"text-slate-500","cssVar":"--text-muted"},"border-default":{"value":"#e2e8f0","tailwind":"border-slate-200","cssVar":"--border-default"},"border-strong":{"value":"#cbd5e1","tailwind":"border-slate-300","cssVar":"--border-strong"},"input-bg":{"value":"#ffffff","tailwind":"bg-white","cssVar":"--input-bg"},"input-border":{"value":"#cbd5e1","tailwind":"border-slate-300","cssVar":"--input-border"},"text-accent":{"value":"#2b70ef","tailwind":"text-primary-500","cssVar":"--text-accent"},"text-on-accent":{"value":"#ffffff","tailwind":"text-white","cssVar":"--text-on-accent"}},"dark":{"bg-page":{"value":"#161718","tailwind":"bg-[var(--bg-page)]","cssVar":"--bg-page"},"bg-page-alt":{"value":"#232525","tailwind":"bg-[var(--bg-page-alt)]","cssVar":"--bg-page-alt"},"bg-surface":{"value":"#1b1c1d","tailwind":"bg-[var(--bg-surface)]","cssVar":"--bg-surface"},"bg-surface-alt":{"value":"#161718","tailwind":"bg-[var(--bg-surface-alt)]","cssVar":"--bg-surface-alt"},"text-heading":{"value":"#eeeeee","tailwind":"text-[var(--text-heading)]","cssVar":"--text-heading"},"text-default":{"value":"#eeeeee","tailwind":"text-[var(--text-default)]","cssVar":"--text-default"},"text-muted":{"value":"#a3a3a3","tailwind":"text-[var(--text-muted)]","cssVar":"--text-muted"},"border-default":{"value":"#373839","tailwind":"border-[var(--border-default)]","cssVar":"--border-default"},"border-strong":{"value":"#777777","tailwind":"border-[var(--border-strong)]","cssVar":"--border-strong"},"input-bg":{"value":"#161718","tailwind":"bg-[var(--input-bg)]","cssVar":"--input-bg"},"input-border":{"value":"#777777","tailwind":"border-[var(--input-border)]","cssVar":"--input-border"},"text-accent":{"value":"#6492ff","tailwind":"text-primary-400","cssVar":"--text-accent"},"text-on-accent":{"value":"#ffffff","tailwind":"text-white","cssVar":"--text-on-accent"}}},"status":{"success":{"base":{"value":"#059669","tailwind":"emerald-600"},"subtle-light":{"value":"#ecfdf5","tailwind":"bg-emerald-50"},"text-light":{"value":"#047857","tailwind":"text-emerald-700"},"subtle-dark":{"value":"rgba(5,150,105,0.12)","tailwind":"bg-emerald-500/[.12]"},"text-dark":{"value":"#6ee7b7","tailwind":"text-emerald-300"}},"warning":{"base":{"value":"#d97706","tailwind":"amber-600"},"subtle-light":{"value":"#fffbeb","tailwind":"bg-amber-50"},"text-light":{"value":"#b45309","tailwind":"text-amber-700"},"subtle-dark":{"value":"rgba(217,119,6,0.12)","tailwind":"bg-amber-500/[.12]"},"text-dark":{"value":"#fcd34d","tailwind":"text-amber-300"}},"danger":{"base":{"value":"#dc2626","tailwind":"red-600"},"subtle-light":{"value":"#fef2f2","tailwind":"bg-red-50"},"text-light":{"value":"#b91c1c","tailwind":"text-red-700"},"subtle-dark":{"value":"rgba(220,38,38,0.12)","tailwind":"bg-red-600/[.12]"},"text-dark":{"value":"#fca5a5","tailwind":"text-red-300"}}}},"typography":{"fontFamily":{"sans":{"value":["Inter","Hiragino Sans","Hiragino Kaku Gothic ProN","Noto Sans JP","sans-serif"],"tailwind":"font-sans"},"mono":{"value":["JetBrains Mono","SF Mono","monospace"],"tailwind":"font-mono"}},"fontSize":{"xxs":{"size":"0.625rem","px":10,"lineHeight":"1.4","tailwind":"text-xxs"},"xs":{"size":"0.8125rem","px":13,"lineHeight":"1.4","tailwind":"text-xs"},"sm":{"size":"0.9375rem","px":15,"lineHeight":"1.7","tailwind":"text-sm"},"base":{"size":"1.125rem","px":18,"lineHeight":"2.0","tailwind":"text-base"},"lg":{"size":"1.25rem","px":20,"lineHeight":"1.5","tailwind":"text-lg"},"xl":{"size":"1.375rem","px":22,"lineHeight":"1.4","tailwind":"text-xl"},"2xl":{"size":"1.625rem","px":26,"lineHeight":"1.4","tailwind":"text-2xl"},"3xl":{"size":"2rem","px":32,"lineHeight":"1.4","tailwind":"text-3xl"}},"fontWeight":{"normal":{"value":400,"tailwind":"font-normal"},"medium":{"value":500,"tailwind":"font-medium"},"semibold":{"value":600,"tailwind":"font-semibold"},"bold":{"value":700,"tailwind":"font-bold"}},"letterSpacing":{"heading":{"value":"0.01em"},"body":{"value":"0.02em"}},"lineHeight":{"heading":{"value":"1.4"},"subheading":{"value":"1.5"},"small":{"value":"1.7"},"body":{"value":"2.0"}}},"spacing":{"1":{"value":"4px","rem":"0.25rem","tailwind":"1"},"2":{"value":"8px","rem":"0.5rem","tailwind":"2"},"3":{"value":"12px","rem":"0.75rem","tailwind":"3"},"4":{"value":"16px","rem":"1rem","tailwind":"4"},"5":{"value":"20px","rem":"1.25rem","tailwind":"5"},"6":{"value":"24px","rem":"1.5rem","tailwind":"6"},"8":{"value":"32px","rem":"2rem","tailwind":"8"},"10":{"value":"40px","rem":"2.5rem","tailwind":"10"},"12":{"value":"48px","rem":"3rem","tailwind":"12"},"14":{"value":"56px","rem":"3.5rem","tailwind":"14"},"16":{"value":"64px","rem":"4rem","tailwind":"16"}},"elevation":{"none":{"value":"none","tailwind":"shadow-none"},"sm":{"value":"0 1px 2px rgba(0,0,0,0.05)","tailwind":"shadow-sm"},"md":{"value":"0 4px 6px rgba(0,0,0,0.1)","tailwind":"shadow-md"},"overlay":{"value":"0 20px 25px rgba(0,0,0,0.1)","tailwind":"shadow-xl"}},"radius":{"sm":{"value":"0.25rem","px":4,"tailwind":"rounded"},"md":{"value":"0.5rem","px":8,"tailwind":"rounded-lg"},"lg":{"value":"0.75rem","px":12,"tailwind":"rounded-xl"},"full":{"value":"9999px","px":9999,"tailwind":"rounded-full"}},"motion":{"duration":{"fast":{"value":"150ms","tailwind":"duration-150"},"normal":{"value":"200ms","tailwind":"duration-200"},"slow":{"value":"300ms","tailwind":"duration-300"}},"easing":{"default":{"value":"cubic-bezier(0.4, 0, 0.2, 1)","tailwind":"ease-in-out"},"in":{"value":"cubic-bezier(0.4, 0, 1, 1)","tailwind":"ease-in"},"out":{"value":"cubic-bezier(0, 0, 0.2, 1)","tailwind":"ease-out"}}},"zIndex":{"base":{"value":0,"tailwind":"z-0"},"dropdown":{"value":20,"tailwind":"z-20"},"sticky":{"value":30,"tailwind":"z-30"},"overlay":{"value":40,"tailwind":"z-40"},"modal":{"value":50,"tailwind":"z-50"}},"wireframe":{"bg":{"value":"#FFFFFF","cssVar":"--wf-bg","tailwind":"wf-bg"},"surface":{"value":"#F5F5F5","cssVar":"--wf-surface","tailwind":"wf-surface"},"border":{"value":"#E0E0E0","cssVar":"--wf-border","tailwind":"wf-border"},"text":{"value":"#333333","cssVar":"--wf-text","tailwind":"wf-text"},"text-sub":{"value":"#888888","cssVar":"--wf-text-sub","tailwind":"wf-text-sub"},"accent":{"value":"#666666","cssVar":"--wf-accent","tailwind":"wf-accent"}}}


===== design/contracts/rules.json =====

{"version":"2.1.0","description":"melta UI 禁止ルール registry。foundations/prohibited.md の machine-readable 版(SSOT)。","schemaVersion":1,"vocabulary":{"ruleCategories":["accessibility","ai-pattern","baseline","button","color","datepicker","divider","form","list","modal","motion","philosophy","skeleton","spacing","stepper","table","tag","typography"],"componentCategories":["data-display","feedback","form-input","layout","navigation"]},"rules":[{"id":"COLOR_NO_TEXT_BLACK","category":"color","severity":"error","description":"純黒はコントラストが強すぎて長時間の利用で目が疲れる","detector":"tailwind-class","pattern":"text-black","alternative":"text-slate-900","contractLint":"enforce"},{"id":"COLOR_NO_ARBITRARY_TEXT_HEX","category":"color","severity":"warn","description":"text-[#...] / text-[rgb(...)] / text-[hsl(...)] / text-[black] 等で色を直書きすると tokens.json のパレット外になりセマンティックカラー原則を回避できてしまう(最頻の検知すり抜け)。フォントサイズの text-[1rem] 等は対象外","detector":"tailwind-class-prefix","pattern":"text-[#","prefixPatterns":["text-[rgb","text-[hsl","text-[oklch","text-[black]","text-[white]"],"alternative":"text-slate-900 / text-primary-600 などカラートークンを使う","contractLint":"warn"},{"id":"COLOR_NO_ARBITRARY_BG_HEX","category":"color","severity":"warn","description":"bg-[#...] / bg-[rgb(...)] / bg-[hsl(...)] / bg-[black] 等で背景色を直書きするとパレット外の色が混入する。bg-[url(...)] 等は対象外","detector":"tailwind-class-prefix","pattern":"bg-[#","prefixPatterns":["bg-[rgb","bg-[hsl","bg-[oklch","bg-[black]","bg-[white]"],"alternative":"bg-white / bg-slate-50 / bg-primary-500 などカラートークンを使う","contractLint":"warn"},{"id":"COLOR_NO_ARBITRARY_BORDER_HEX","category":"color","severity":"warn","description":"border-[#...] / border-[rgb(...)] / border-[hsl(...)] / border-[black] 等で枠線色を直書きするとパレット外の色が混入する。border-[1px] 等の太さ指定は対象外","detector":"tailwind-class-prefix","pattern":"border-[#","prefixPatterns":["border-[rgb","border-[hsl","border-[oklch","border-[black]","border-[white]"],"alternative":"border-slate-200 / border-primary-500 などカラートークンを使う","contractLint":"warn"},{"id":"SPACE_NO_ARBITRARY_SHADOW","category":"spacing","severity":"warn","description":"shadow-[...] で影を直書きすると elevation トークンを回避でき、過剰な影で安っぽく見える","detector":"tailwind-class-prefix","pattern":"shadow-[","alternative":"shadow-sm / shadow-md など elevation トークンを使う","contractLint":"warn"},{"id":"TYPO_NO_ARBITRARY_FONT","category":"typography","severity":"warn","description":"font-[...] で font-weight / font-family を直書きすると typography トークンを回避できる(font-[300] など細すぎる weight の混入経路)","detector":"tailwind-class-prefix","pattern":"font-[","alternative":"font-normal / font-medium / font-semibold などタイポグラフィトークンを使う","contractLint":"warn"},{"id":"COLOR_NO_INLINE_STYLE_HARDCODE","category":"color","severity":"warn","description":"inline style で色をハードコードするとカラールール(class 検査)を迂回できる。var(--...) 経由の CSS 変数は対象外で、# / rgb / hsl の直書きのみ検知する","detector":"html-attr","pattern":null,"alternative":"Tailwind カラートークン(bg-primary-600 等) か CSS 変数 var(--text-default) を使う","contractLint":"skip","htmlAttrCheck":{"kind":"attr-value-contains","attr":"style","valueRegex":"(?:background|background-color|color|border-color|fill|stroke|box-shadow|outline-color)\\s*:\\s*(?:#|rgb|hsl)"}},{"id":"PHILOSOPHY_NO_STYLE_BLOCK","category":"philosophy","severity":"warn","description":"生 CSS の <style> ブロックは Tailwind トークン体系を迂回する escape hatch。CDN 運用では意図的回避でしか発生しない","detector":"html-attr","pattern":null,"alternative":"Tailwind ユーティリティ / デザイントークンで表現する。どうしても必要なら @layer で正規化","contractLint":"skip","htmlAttrCheck":{"kind":"tag-present","tag":"style"}},{"id":"COLOR_NO_DARK_BG_GRAY","category":"color","severity":"error","description":"テキストのコントラスト確保が困難になる","detector":"tailwind-class-prefix","pattern":"bg-gray-[3-9]00","matchPatterns":["bg-gray-300","bg-gray-400","bg-gray-500","bg-gray-600","bg-gray-700","bg-gray-800","bg-gray-900"],"alternative":"bg-gray-50 〜 bg-gray-200","contractLint":"enforce"},{"id":"COLOR_NO_PRIMARY_400","category":"color","severity":"warn","description":"CTAとして弱く、目立たない","detector":"tailwind-class","pattern":"bg-primary-400","alternative":"bg-primary-500","contractLint":"enforce"},{"id":"COLOR_NO_GRAY_400_BODY","category":"color","severity":"error","description":"WCAG不適合(コントラスト比不足)","detector":"tailwind-class","pattern":"text-gray-400","alternative":"text-body (#3d4b5f)","contractLint":"enforce"},{"id":"COLOR_NO_GRAY_100_BORDER","category":"color","severity":"error","description":"薄すぎて境界が見えない","detector":"tailwind-class","pattern":"border-gray-100","alternative":"border-slate-200","contractLint":"enforce"},{"id":"COLOR_NO_GREEN","category":"color","severity":"error","description":"emeraldで統一する","detector":"tailwind-class-prefix","pattern":"bg-green-","alternative":"bg-emerald-*","contractLint":"enforce"},{"id":"COLOR_NO_YELLOW","category":"color","severity":"error","description":"amberで統一する","detector":"tailwind-class-prefix","pattern":"bg-yellow-","alternative":"bg-amber-*","contractLint":"enforce"},{"id":"COLOR_NO_ROSE","category":"color","severity":"error","description":"redで統一する","detector":"tailwind-class-prefix","pattern":"bg-rose-","alternative":"bg-red-*","contractLint":"enforce"},{"id":"COLOR_NO_BLUE_BG","category":"color","severity":"error","description":"primaryで統一する","detector":"tailwind-class-prefix","pattern":"bg-blue-","alternative":"bg-primary-*","contractLint":"enforce"},{"id":"COLOR_NO_BLUE_LINKS","category":"color","severity":"error","description":"primaryで統一する","detector":"tailwind-class-prefix","pattern":"text-blue-","alternative":"text-primary-500","contractLint":"enforce"},{"id":"COLOR_NO_INDIGO","category":"color","severity":"error","description":"primaryで統一する","detector":"tailwind-class-prefix","pattern":"bg-indigo-","alternative":"bg-primary-*","contractLint":"enforce"},{"id":"COLOR_ONLY_FORBIDDEN","category":"color","severity":"error","description":"色だけで情報伝達すると色覚多様性への非対応になる","detector":"manual","pattern":null,"alternative":"アイコン/テキストを必ず併用","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"PHILOSOPHY_NO_EXCESSIVE_ANIMATION","category":"philosophy","severity":"error","description":"操作の邪魔になり、認知コストを増加させる","detector":"manual","pattern":null,"alternative":"150〜300ms の状態変化フィードバックに限定","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"MOTION_NO_LONG_DURATION","category":"motion","severity":"error","description":"操作が鈍く感じる(Progress フィルバーは例外)","detector":"tailwind-class-prefix","pattern":"duration-[5-9]00|duration-1000","matchPatterns":["duration-500","duration-700","duration-1000"],"alternative":"duration-300 以下","contractLint":"skip","requiresContext":true},{"id":"MOTION_REDUCED_MOTION_REQUIRED","category":"motion","severity":"error","description":"prefers-reduced-motion 無視はアクセシビリティ違反","detector":"manual","pattern":null,"alternative":"メディアクエリで対応","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"TYPO_NO_TRACKING_TIGHT","category":"typography","severity":"error","description":"日本語の可読性が低下する","detector":"tailwind-class","pattern":"tracking-tight","alternative":"tracking-normal 以上(本文2%、見出し1%)","contractLint":"enforce"},{"id":"TYPO_NO_XS_BODY","category":"typography","severity":"error","description":"本文には小さすぎて読みづらい","detector":"manual","pattern":null,"alternative":"text-base(16px)","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"TYPO_NO_FONT_LIGHT","category":"typography","severity":"error","description":"細すぎて可読性が低い","detector":"tailwind-class","pattern":"font-light","alternative":"font-normal(400)以上","contractLint":"enforce"},{"id":"TYPO_NO_PLACEHOLDER_ONLY","category":"typography","severity":"error","description":"入力開始で消え、目的がわからなくなる","detector":"manual","pattern":null,"alternative":"<label> を必ず使用","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"SPACE_NO_ROUNDED_NONE_CARDS","category":"spacing","severity":"error","description":"UIの統一感を損なう","detector":"tailwind-class","pattern":"rounded-none","alternative":"rounded-xl(12px)","contractLint":"skip","requiresContext":true},{"id":"SPACE_NO_SHADOW_LG","category":"spacing","severity":"error","description":"影が強すぎてノイズになる","detector":"tailwind-class","pattern":"shadow-lg","alternative":"shadow-sm 〜 shadow-md(オーバーレイ: shadow-xl)","contractLint":"enforce"},{"id":"SPACE_NO_SHADOW_2XL","category":"spacing","severity":"error","description":"影が強すぎてノイズになる","detector":"tailwind-class","pattern":"shadow-2xl","alternative":"shadow-sm 〜 shadow-md(オーバーレイ: shadow-xl)","contractLint":"enforce"},{"id":"SPACE_NO_PY_05_BTN","category":"spacing","severity":"error","description":"タップターゲットが小さすぎる","detector":"tailwind-class","pattern":"py-0.5","alternative":"h-8 以上(S: h-8 / M: h-10 / L: h-12)","contractLint":"skip","requiresContext":true},{"id":"SPACE_NO_P0_CARDS","category":"spacing","severity":"error","description":"コンテンツが窮屈になる","detector":"tailwind-class","pattern":"p-0","alternative":"p-5 以上","contractLint":"skip","requiresContext":true},{"id":"SPACE_NO_GAP0_SECTIONS","category":"spacing","severity":"warn","description":"セクションの区切りが不明瞭","detector":"tailwind-class","pattern":"gap-0","alternative":"gap-6 以上","contractLint":"skip","requiresContext":true},{"id":"SPACE_NO_M0_PAGE","category":"spacing","severity":"warn","description":"ページ端にコンテンツが張り付く","detector":"manual","pattern":null,"alternative":"px-6 py-8 以上","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"SPACE_NO_DARK_SIDEBAR_BG","category":"spacing","severity":"error","description":"メインコンテンツとのコントラストが強すぎる","detector":"manual","pattern":null,"alternative":"bg-white + ボーダー","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"SPACE_NO_NONSTANDARD_SIDEBAR_WIDTH","category":"spacing","severity":"error","description":"実装ごとにバラつきが出る","detector":"tailwind-class","pattern":"w-60","alternative":"w-64(標準)or w-16(コンパクト)","contractLint":"skip","requiresContext":true},{"id":"SPACE_NO_ROUNDED_XL_NAV","category":"spacing","severity":"error","description":"ボタン等他コンポーネントとの一貫性を損なう","detector":"manual","pattern":null,"alternative":"rounded-lg","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"SPACE_NO_LARGE_NAV_ICON","category":"spacing","severity":"error","description":"DS標準アイコンサイズからの逸脱","detector":"manual","pattern":null,"alternative":"w-5 h-5","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"SPACE_NO_DRAWER_NO_FOCUS_TRAP","category":"spacing","severity":"error","description":"キーボードユーザーが背面要素を操作してしまう","detector":"manual","pattern":null,"alternative":"フォーカストラップを実装","contractLint":"skip","automationStatus":"human-only"},{"id":"SPACE_NO_MISSING_ARIA_CURRENT","category":"spacing","severity":"error","description":"スクリーンリーダーが現在ページを識別できない","detector":"html-attr","pattern":null,"alternative":"Active ナビアイテムに aria-current=\"page\" を付与","contractLint":"skip","automationStatus":"impossible-static"},{"id":"SPACE_NO_3COL_LAYOUT","category":"spacing","severity":"warn","description":"認知負荷が高い","detector":"manual","pattern":null,"alternative":"サイドバー + メインの2列","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"AI_NO_CARD_COLOR_BAR_TOP","category":"ai-pattern","severity":"error","description":"AI生成UIの典型パターン。装飾過剰で汎用性が低い","detector":"tailwind-class","pattern":"border-t-4","alternative":"border border-slate-200 のみでカードを構成","contractLint":"enforce"},{"id":"AI_NO_CARD_COLOR_BAR_LEFT","category":"ai-pattern","severity":"error","description":"Alert含め全コンポーネントで禁止","detector":"tailwind-class","pattern":"border-l-4","alternative":"border border-*-200 rounded-lg で全周ボーダー","contractLint":"enforce"},{"id":"AI_NO_GRADIENT_BG","category":"ai-pattern","severity":"error","description":"装飾的なグラデーション背景はAI生成UIの典型tell。安っぽく見える","detector":"tailwind-class-prefix","pattern":"bg-gradient-","alternative":"単色の bg-primary-500 / bg-white / bg-slate-50 を使う","contractLint":"enforce"},{"id":"AI_NO_DECORATIVE_PURPLE","category":"ai-pattern","severity":"error","description":"purple/violet/fuchsia 系の装飾カラーはAI生成UIの典型tell。brand colorを使う","detector":"tailwind-class-segment","pattern":null,"matchPatterns":["purple","violet","fuchsia"],"alternative":"bg-primary-* / text-primary-* (brand color)を使う","contractLint":"enforce"},{"id":"BTN_NO_SAME_STYLE_PARALLEL","category":"button","severity":"warn","description":"重要度の区別がつかない(Neutralのみ例外)","detector":"manual","pattern":null,"alternative":"階層の異なるボタンを組み合わせる","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"BTN_NO_LIGHTED_SOLO","category":"button","severity":"warn","description":"トグル状態の対比がないと意味不明","detector":"manual","pattern":null,"alternative":"Neutralとペアで使用","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"BTN_ICON_ONLY_ARIA_REQUIRED","category":"button","severity":"error","description":"操作内容がスクリーンリーダーに伝わらない","detector":"composition","pattern":null,"alternative":"aria-label=\"閉じる\" 等を付与","contractLint":"skip","compositionCheck":{"kind":"dom-attr-required","selector":"button","requireAnyAttr":["aria-label","aria-labelledby","title"],"when":"icon-only"},"automationStatus":"auto"},{"id":"BTN_MIN_TAP_TARGET","category":"button","severity":"error","description":"高さ 44px 未満のボタン(h-6〜h-10)は当たり判定拡張が無いとモバイルで操作困難(WCAG 2.2 SC 2.5.5 Target Size (Enhanced) = AAA の 44px 水準。AA の SC 2.5.8 は 24px だが melta は 44px を採る。インラインテキストリンクを除く)。見た目を変えず after: 擬似要素でタップ領域だけ広げる。icon-only ボタンは幅拡張が別式のため第一弾対象外(2026-07-19 に manual から composition 自動検出へ昇格)。横断方針は A11Y_MIN_TAP_TARGET_44 が正。本ルールはその web(button)実装形","detector":"composition","pattern":null,"alternative":"relative after:absolute after:inset-x-0 after:top-1/2 after:h-11 after:-translate-y-1/2 を付与(button recipe 準拠なら自動で付く)","contractLint":"skip","compositionCheck":{"kind":"dom-class-required","selector":"button.h-6, button.h-7, button.h-8, button.h-9, button.h-10","requireAnyClass":["after:h-11","min-h-11"],"excludeWhen":"icon-only"},"automationStatus":"auto"},{"id":"FORM_SELECT_APPEARANCE_NONE","category":"form","severity":"error","description":"ネイティブ矢印はブラウザ間で位置・余白が不安定","detector":"manual","pattern":null,"alternative":"appearance-none + pr-10 + カスタムSVGシェブロン","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"FORM_NO_LABEL_OMIT","category":"form","severity":"error","description":"スクリーンリーダーが目的を読み上げられない","detector":"manual","pattern":null,"alternative":"<label> を for 属性で関連付け","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"FORM_NO_SIDE_LABEL","category":"form","severity":"warn","description":"モバイルで破綻し、視線移動が増える","detector":"manual","pattern":null,"alternative":"ラベルは入力欄の上","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"FORM_FIELDSET_LEGEND_REQUIRED","category":"form","severity":"error","description":"グループの目的が伝わらない","detector":"manual","pattern":null,"alternative":"グループ時は <fieldset> / <legend> を使用","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"FORM_NO_AUTO_HIDE_ERROR","category":"form","severity":"error","description":"ユーザーが読む前に消える","detector":"manual","pattern":null,"alternative":"修正されるまで表示","contractLint":"skip","automationStatus":"human-only"},{"id":"FORM_NO_COLOR_ONLY_ERROR","category":"form","severity":"error","description":"色覚多様性への非対応","detector":"manual","pattern":null,"alternative":"ボーダー色 + エラーアイコン + テキスト","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"FORM_NO_CARD_FIELDSET_LEGEND","category":"form","severity":"error","description":"<legend> のブラウザデフォルト描画がカードの border と干渉する","detector":"manual","pattern":null,"alternative":"カードレベルは <div> + <h2>。<fieldset>/<legend> はカード内部のフォームグループに限定","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"FORM_NO_DATE_EQUAL_WIDTH","category":"form","severity":"warn","description":"月・日セレクトが不必要に広くなり選択しにくい","detector":"manual","pattern":null,"alternative":"flex レイアウトで年 w-28、月・日 w-20 に固定","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"FORM_NO_CHECK_ONLY_CONFIRM","category":"form","severity":"error","description":"意図しない確定が起きる","detector":"manual","pattern":null,"alternative":"確認ボタンを必ず配置","contractLint":"skip","automationStatus":"human-only"},{"id":"FORM_NO_AUTO_FOCUS_MOVE","category":"form","severity":"error","description":"ユーザーを混乱させる","detector":"manual","pattern":null,"alternative":"ユーザー操作に任せる","contractLint":"skip","automationStatus":"human-only"},{"id":"FORM_NO_DISTANT_ERROR","category":"form","severity":"error","description":"フィールドとの対応がわからない","detector":"manual","pattern":null,"alternative":"フィールド直下に表示","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"MODAL_FOCUS_TRAP_REQUIRED","category":"modal","severity":"error","description":"キーボードユーザーがモーダル外に出てしまう","detector":"manual","pattern":null,"alternative":"Tab/Shift+Tabがモーダル内を循環","contractLint":"skip","automationStatus":"covered-by-test"},{"id":"MODAL_ESC_CLOSE_REQUIRED","category":"modal","severity":"error","description":"ユーザーが脱出できない","detector":"manual","pattern":null,"alternative":"Escキーで閉じる","contractLint":"skip","automationStatus":"covered-by-test"},{"id":"MODAL_CLOSE_REQUIRED","category":"modal","severity":"error","description":"ユーザーが操作を中断できない","detector":"manual","pattern":null,"alternative":"閉じるボタン + Esc + オーバーレイクリック","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"MODAL_ROLE_DIALOG_REQUIRED","category":"modal","severity":"error","description":"スクリーンリーダーがモーダルを認識できない","detector":"html-attr","pattern":null,"alternative":"role=\"dialog\" を必ず付与","contractLint":"skip","automationStatus":"covered-by-test"},{"id":"MODAL_OVERLAY_REQUIRED","category":"modal","severity":"error","description":"背景との分離が不明確","detector":"manual","pattern":null,"alternative":"bg-black/50 のオーバーレイ","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"MODAL_NO_NESTED","category":"modal","severity":"error","description":"モーダルの中にモーダルを開くとUXが複雑になりすぎる。合法な部品だけで構成しても合成として崩壊する","detector":"composition","pattern":null,"alternative":"設計を見直す(role=dialog を2階層以上ネストしない)","contractLint":"skip","compositionCheck":{"kind":"nested-selector","selector":"[role=\"dialog\"]"}},{"id":"A11Y_NO_NESTED_INTERACTIVE","category":"accessibility","severity":"error","description":"インタラクティブ要素の入れ子(button/a/role=button の中に別のインタラクティブ要素)は HTML 仕様上不正で、キーボード操作・スクリーンリーダー・クリック判定が壊れる。合法な部品でも組み方で崩壊する典型","detector":"composition","pattern":null,"alternative":"入れ子を解消する。クリック領域を分ける、外側を div 等の非インタラクティブ要素にする、または stretched-link パターンを使う","contractLint":"skip","compositionCheck":{"kind":"nested-selector","selector":"a[href], button, [role=\"button\"]"}},{"id":"LIST_NO_FIXED_HEIGHT_MISMATCH","category":"list","severity":"error","description":"テキストが切れる or 余白が不均等","detector":"manual","pattern":null,"alternative":"可変高さにする","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"LIST_NO_COLOR_ONLY_SELECTION","category":"list","severity":"error","description":"色覚多様性への非対応","detector":"manual","pattern":null,"alternative":"ボーダー太さ + 背景スタイルを併用","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"LIST_NO_GESTURE_ONLY","category":"list","severity":"error","description":"キーボード/スクリーンリーダーで操作不可","detector":"manual","pattern":null,"alternative":"ボタンによる代替操作を提供","contractLint":"skip","automationStatus":"human-only"},{"id":"LIST_NO_ICON_BORDER","category":"list","severity":"warn","description":"情報の断絶を誤解させる","detector":"manual","pattern":null,"alternative":"ボーダーはアイテム間のみ","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"TABLE_NO_LAYOUT_TABLE","category":"table","severity":"error","description":"セマンティクス違反","detector":"manual","pattern":null,"alternative":"flex / grid を使う","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"TABLE_TH_SCOPE_REQUIRED","category":"table","severity":"error","description":"ヘッダーとデータの関係が不明確","detector":"html-attr","pattern":null,"alternative":"scope=\"col\" を付与","contractLint":"skip","htmlAttrCheck":{"kind":"tag-missing-attr","tag":"th","requiredAttr":"scope"}},{"id":"TAG_REMOVABLE_X_REQUIRED","category":"tag","severity":"error","description":"キーボードのみでは削除操作を発見できない","detector":"manual","pattern":null,"alternative":"×ボタンを必ず表示","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"TAG_X_MIN_TAP_TARGET","category":"tag","severity":"error","description":"モバイルで誤タップが頻発する。横断方針は A11Y_MIN_TAP_TARGET_44 が正。本ルールはその web(tag の × ボタン)実装形","detector":"manual","pattern":null,"alternative":"p-0.5 + SVG w-3 h-3(実質24px以上)","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"TAG_X_ARIA_LABEL_REQUIRED","category":"tag","severity":"error","description":"スクリーンリーダーがボタンの目的を読み上げられない","detector":"composition","pattern":null,"alternative":"aria-label=\"{タグ名}を削除\" を付与","contractLint":"skip","compositionCheck":{"kind":"dom-attr-required","selector":"button","requireAnyAttr":["aria-label","aria-labelledby"],"when":"text-glyph","glyphs":["×","✕","✖","╳","⨯"]},"automationStatus":"auto"},{"id":"TAG_FILTER_ARIA_SELECTED_REQUIRED","category":"tag","severity":"error","description":"選択状態がスクリーンリーダーに伝わらない","detector":"html-attr","pattern":null,"alternative":"aria-selected=\"true\" / \"false\" を付与","contractLint":"skip","automationStatus":"impossible-static"},{"id":"TAG_BADGE_CONFUSION","category":"tag","severity":"warn","description":"Badge はステータス表示、Tag はユーザー管理メタデータ","detector":"manual","pattern":null,"alternative":"用途に応じて badge / tag を使い分ける","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"DIVIDER_NO_DIV_BORDER_B","category":"divider","severity":"error","description":"セマンティクス違反。支援技術が区切りを認識できない","detector":"manual","pattern":null,"alternative":"<hr> or role=\"separator\"","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"DIVIDER_NO_GRAY_100","category":"divider","severity":"error","description":"薄すぎて境界が見えない","detector":"tailwind-class","pattern":"border-gray-100","alternative":"border-slate-200","contractLint":"enforce"},{"id":"DIVIDER_NO_SLATE_400_PLUS","category":"divider","severity":"warn","description":"線が強すぎてノイズになる","detector":"manual","pattern":null,"alternative":"border-slate-200(標準)/ border-slate-300(強調)","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"STEPPER_NO_COLOR_ONLY_STATE","category":"stepper","severity":"error","description":"色覚多様性への非対応","detector":"manual","pattern":null,"alternative":"アイコン + ボーダー + 背景色を併用","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"STEPPER_ARIA_CURRENT_REQUIRED","category":"stepper","severity":"error","description":"スクリーンリーダーが現在ステップを識別できない","detector":"html-attr","pattern":null,"alternative":"Active ステップに aria-current=\"step\" を付与","contractLint":"skip","automationStatus":"impossible-static"},{"id":"STEPPER_MIN_INDICATOR_SIZE","category":"stepper","severity":"error","description":"タップターゲットが小さすぎる","detector":"manual","pattern":null,"alternative":"w-8 h-8(標準)/ w-6 h-6(コンパクト最小)","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"STEPPER_NO_DARK_CONNECTOR","category":"stepper","severity":"warn","description":"線が強すぎてノイズになる","detector":"manual","pattern":null,"alternative":"bg-primary-500(完了区間)/ bg-slate-200(未着手区間)","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"DATEPICKER_NO_NATIVE_INPUT","category":"datepicker","severity":"warn","description":"ブラウザ間で表示が不統一","detector":"html-attr","pattern":null,"alternative":"カスタム Date Picker を使用","contractLint":"skip","htmlAttrCheck":{"kind":"element-present","tag":"input","attr":"type","attrValue":"date"}},{"id":"DATEPICKER_NO_SHADOW_LG","category":"datepicker","severity":"error","description":"影が強すぎてノイズになる(datepicker コンテキスト。汎用は SPACE_NO_SHADOW_LG で検出)","detector":"manual","pattern":null,"alternative":"shadow-md","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"DATEPICKER_Z_INDEX_20","category":"datepicker","severity":"error","description":"Dropdown レイヤーの統一が崩れる","detector":"manual","pattern":null,"alternative":"z-20(Dropdown レイヤー)","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"DATEPICKER_NO_COLOR_ONLY_TODAY","category":"datepicker","severity":"error","description":"色覚多様性への非対応","detector":"manual","pattern":null,"alternative":"font-semibold を併用","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"DATEPICKER_KEYBOARD_NAV_REQUIRED","category":"datepicker","severity":"error","description":"キーボードユーザーが操作不可","detector":"manual","pattern":null,"alternative":"矢印 + Enter + Escape を実装","contractLint":"skip","automationStatus":"human-only"},{"id":"DATEPICKER_WEEKDAY_HEADER_REQUIRED","category":"datepicker","severity":"error","description":"日付の曜日が判別できない","detector":"manual","pattern":null,"alternative":"日〜土のラベルを必ず表示","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"SKELETON_BG_SLATE_200_ONLY","category":"skeleton","severity":"error","description":"DS統一から外れる","detector":"manual","pattern":null,"alternative":"bg-slate-200 固定","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"SKELETON_NO_SPINNER_ONLY","category":"skeleton","severity":"warn","description":"進捗が伝わらず不安を与える","detector":"manual","pattern":null,"alternative":"スケルトン or プログレスバーを併用","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"SKELETON_ARIA_BUSY_REQUIRED","category":"skeleton","severity":"error","description":"スクリーンリーダーがローディング状態を認識できない","detector":"composition","pattern":null,"alternative":"コンテナに aria-busy=\"true\" + role=\"status\"","contractLint":"skip","compositionCheck":{"kind":"dom-attr-required","selector":".skeleton-pulse","requireAnyAttr":["aria-busy"],"scope":"ancestor-or-self"},"automationStatus":"auto"},{"id":"SKELETON_ARIA_BUSY_RELEASE","category":"skeleton","severity":"error","description":"ローディング完了が伝わらない","detector":"manual","pattern":null,"alternative":"aria-busy=\"false\" に変更","contractLint":"skip","automationStatus":"human-only"},{"id":"A11Y_NO_OUTLINE_NONE_WITHOUT_RING","category":"accessibility","severity":"error","description":"フォーカスインジケーターが消える","detector":"manual","pattern":null,"alternative":"focus:ring-2 focus:ring-primary-500/50","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"A11Y_NO_TABINDEX_POSITIVE","category":"accessibility","severity":"error","description":"フォーカス順序が混乱する","detector":"html-attr","pattern":null,"alternative":"DOM順に従い、tabindex=\"0\" or \"-1\" のみ使用","contractLint":"skip","htmlAttrCheck":{"kind":"attr-value-forbidden","attr":"tabindex","valueRegex":"^[1-9][0-9]*$"}},{"id":"A11Y_NO_TIME_LIMIT","category":"accessibility","severity":"error","description":"ユーザーが操作を完了できない可能性","detector":"manual","pattern":null,"alternative":"時間制限を設けない","contractLint":"skip","automationStatus":"human-only"},{"id":"A11Y_NO_DECORATIVE_ANIMATION","category":"accessibility","severity":"warn","description":"動きに敏感なユーザーへの配慮不足","detector":"manual","pattern":null,"alternative":"状態変化のフィードバックのみ","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"A11Y_NO_TEXT_TRUNCATION_200","category":"accessibility","severity":"error","description":"コンテンツにアクセスできなくなる","detector":"manual","pattern":null,"alternative":"レスポンシブに対応","contractLint":"skip","automationStatus":"human-only"},{"id":"A11Y_DISABLED_REQUIRES_ARIA","category":"accessibility","severity":"warn","description":"disabled 属性単独では支援技術への状態通知が実装依存になる。契約(button stateSpecs.disabled)の規範どおり aria-disabled=\"true\" を併記し、視覚状態クラス(opacity-50 cursor-not-allowed)とセットにする。タブ順維持が要る文脈(ツールバー/ページネーション)では aria-disabled 単独 + JS click ガードも可(DESIGN.md 注記参照)","detector":"composition","pattern":null,"alternative":"disabled aria-disabled=\"true\" class=\"opacity-50 cursor-not-allowed ...\"(契約 stateSpecs.disabled の tailwind 準拠)","contractLint":"skip","compositionCheck":{"kind":"dom-attr-required","selector":"button[disabled]","requireAnyAttr":["aria-disabled"]}},{"id":"A11Y_MIN_TAP_TARGET_44","category":"accessibility","severity":"error","description":"すべての操作要素は実効タップ標的 44pt(web は 44px)を下回らない — melta の横断方針(WCAG 2.2 SC 2.5.5 Target Size (Enhanced) = AAA の 44px 水準を採る。AA の SC 2.5.8 は 24px だが melta はそこで止めない。インラインテキストリンクは例外)。視覚寸法は契約どおり据え置き、当たり判定だけを広げる: web は h-8/h-10 のまま after: 擬似要素で 44px(または min-h-11)、app は視覚 24pt + hitSlop 10 の正典パターンか minHeight で下限を保証する(height 固定は fontScale でクリップするので使わない)。コンポーネント別の BTN_MIN_TAP_TARGET / TAG_X_MIN_TAP_TARGET は本方針の実装形であり、方針そのものの正本は本ルール","detector":"manual","pattern":null,"alternative":"視覚寸法は変えずタップ領域だけ拡張する。web: relative after:absolute after:inset-x-0 after:top-1/2 after:h-11 after:-translate-y-1/2(または min-h-11)/ app: hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }} か minHeight: 44","contractLint":"skip","automationStatus":"llm-judge-candidate"},{"id":"A11Y_NAV_ARIA_LABEL_REQUIRED","category":"accessibility","severity":"error","description":"<nav>(および role=\"navigation\")にアクセシブルネームが無いと、スクリーンリーダーのランドマーク一覧で複数のナビゲーションを区別できない。nav が 1 つしか無い画面でも、後から増えたときに無名ランドマークが並ぶため常に付与する","detector":"composition","pattern":null,"alternative":"<nav aria-label=\"メインナビゲーション\"> のように aria-label を付与する(見出し要素を指す aria-labelledby でもよい)。空文字・空白のみの値はアクセシブルネームにならないので不可。aria-labelledby の参照先の存在は静的検査しない(fragment 検査では参照先が文書外にあるのが常態のため。design-review の目視で確認する)","contractLint":"skip","compositionCheck":{"kind":"dom-attr-required","selector":"nav, [role~=\"navigation\" i]","requireAnyAttr":["aria-label","aria-labelledby"]},"automationStatus":"auto"},{"id":"BASELINE_NO_ANCHOR_POSITIONING","category":"baseline","severity":"warn","description":"CSS Anchor Positioning は Baseline Limited(2026-07 時点, webstatus.dev)。fallback なしでは非対応ブラウザで配置が崩壊する。Baseline Widely available 未達機能は fallback 併記 + コメント明示宣言がない限り使わない","detector":"tailwind-class-prefix","pattern":"[anchor-name:","prefixPatterns":["[position-anchor:","[position-area:","[position-try"],"alternative":"absolute + top/left トークン系ユーティリティによる従来配置(DESIGN.md の配置パターン準拠)","contractLint":"warn"},{"id":"BASELINE_NO_INVOKER_COMMANDS","category":"baseline","severity":"warn","description":"Invoker Commands(commandfor / command 属性)は Baseline Limited(2026-07 時点)。非対応ブラウザではボタンが完全に無反応になる","detector":"html-attr","pattern":null,"alternative":"明示的な JS イベントリスナー、または dialog は showModal() 呼び出しで開閉する","contractLint":"skip","htmlAttrCheck":{"kind":"attr-present","attr":"(?:commandfor|command)"}},{"id":"BASELINE_NO_POPOVER_ATTR","category":"baseline","severity":"warn","description":"popover 属性は Baseline Newly → Widely 境界(2026-07 時点)。polyfill なしの生成では古い環境で開閉不能になる。使う場合は fallback かコメント明示宣言を伴うこと","detector":"html-attr","pattern":null,"alternative":"dropdown/tooltip contract の実装パターン(絶対配置 + JS toggle)を使う","contractLint":"skip","htmlAttrCheck":{"kind":"attr-present","attr":"popover"}},{"id":"BASELINE_NO_VIEW_TRANSITION","category":"baseline","severity":"warn","description":"View Transitions は same-document が Baseline Newly / cross-document が Limited(2026-07 時点)。演出前提の UI 構造にすると非対応環境で意味が壊れる","detector":"tailwind-class-prefix","pattern":"[view-transition-name:","prefixPatterns":["[view-transition-class:"],"alternative":"motion トークン(duration/easing)による CSS transition で代替する","contractLint":"warn"},{"id":"BASELINE_NO_TEXT_BOX_TRIM","category":"baseline","severity":"warn","description":"text-box-trim / text-box-edge は Baseline Newly(2026-07 時点)。行ボックスの光学調整に依存したレイアウトは非対応環境で余白がズレる","detector":"tailwind-class-prefix","pattern":"[text-box-trim:","prefixPatterns":["[text-box-edge:","[text-box:"],"alternative":"spacing トークン(py-* / leading-*)で余白を明示指定する","contractLint":"warn"}]}


===== contract summaries(全 40 contract。全文は design/contracts/components/{id}.contract.json) =====

{"id":"accordion","description":"折りたたみ式コンテンツ。aria-expanded必須。","variants":["single","multiple"],"states":["default","expanded","collapsed","hover","focus"],"anatomy":["container","item","trigger","icon","panel"],"rules":[]}
{"id":"action-sheet","description":"画面下から出るアクション/選択リスト。web の select / dropdown を APP に adapted 変換する際の受け皿(構造的 P0)。destructive アクションは色で区別しラベルでも伝える。","webStatus":"pending","variants":["default"],"states":["default"],"anatomy":["overlay","sheet","title?","action","cancelAction"],"rules":[]}
{"id":"alert","description":"インラインアラート通知。Info / Success / Warning / Error の4タイプ。","variants":["info","success","warning","error"],"states":["default","dismissing"],"anatomy":["container","icon","title?","message","closeButton?"],"rules":["COLOR_ONLY_FORBIDDEN","AI_NO_CARD_COLOR_BAR_LEFT","AI_NO_CARD_COLOR_BAR_TOP"]}
{"id":"avatar","description":"ユーザーアバター。Image / Initials / Status / Group。","variants":["image","initials","group"],"states":["default","online","away","offline"],"anatomy":["container","image?","initials?","statusDot?"],"rules":[]}
{"id":"badge","description":"ステータス・カウント表示。Status / Dot / Count / Outline の4バリエーション。","variants":["neutral","success","warning","danger","accent"],"states":["default"],"anatomy":["container","dotIndicator?","label"],"rules":["COLOR_ONLY_FORBIDDEN","TAG_BADGE_CONFUSION"]}
{"id":"bottom-sheet","description":"画面下から出る汎用シート container(content は自由 slot)。フィルタ・詳細・複雑な選択 UI の受け皿。ActionSheet がリスト特化なのに対しこちらは容器。","webStatus":"pending","variants":["default"],"states":["default"],"anatomy":["overlay","sheet","grabber","title?","content"],"rules":[]}
{"id":"breadcrumb","description":"階層パスナビゲーション。ol要素で構造化。","variants":["text-separator","chevron-separator"],"states":["default","hover"],"anatomy":["nav","orderedList","linkItem","separator","currentPage","ellipsis?","homeIcon?"],"rules":["SPACE_NO_MISSING_ARIA_CURRENT","A11Y_NAV_ARIA_LABEL_REQUIRED"]}
{"id":"button","description":"CTA / secondary / icon button。3階層ヒエラルキー。","variants":["contained","outlined","brand-outline","neutral","lighted","danger","subtle"],"states":["default","hover","focus","disabled","loading"],"stateSpecs":{"disabled":{"description":"操作不可。全 variant 共通。","tailwind":"opacity-50 cursor-not-allowed pointer-events-none","ariaChanges":"disabled 属性 + aria-disabled=\"true\"。hover/focus は効かせない。"},"loading":{"description":"非同期処理中。全 variant 共通。","tailwind":"opacity-70 cursor-wait pointer-events-none","ariaChanges":"aria-busy=\"true\" + disabled。","htmlNote":"label 前にスピナーを prepend(スピナーのクラスは htmlSample/anatomy 側で表現。htmlNote は prose でリンタ非対象)。"}},"anatomy":["leadingIcon?","label","trailingIcon?"],"rules":["SPACE_NO_PY_05_BTN","BTN_ICON_ONLY_ARIA_REQUIRED","BTN_MIN_TAP_TARGET","BTN_NO_SAME_STYLE_PARALLEL","BTN_NO_LIGHTED_SOLO"]}
{"id":"card","description":"コンテンツコンテナ。Basic / Metrics / Media / Action / Link の5バリエーション。","variants":["basic","media","action","link"],"states":["default","hover","focus-within"],"anatomy":["header?","body","footer?","media?"],"rules":["SPACE_NO_ROUNDED_NONE_CARDS","SPACE_NO_SHADOW_LG","SPACE_NO_SHADOW_2XL","SPACE_NO_P0_CARDS","AI_NO_CARD_COLOR_BAR_TOP","AI_NO_CARD_COLOR_BAR_LEFT"]}
{"id":"checkbox","description":"複数選択フォームコントロール。CSS 18px サイズ。","variants":["default","disabled","indeterminate"],"states":["default","checked","unchecked","indeterminate","disabled","error","focus"],"anatomy":["box","checkmark?","indeterminateMark?","label","groupLabel?","helperText?","errorText?"],"rules":["FORM_NO_LABEL_OMIT"]}
{"id":"copy-button","description":"クリップボードコピー + pop アニメーション付きアイコンボタン。","variants":["outlined","subtle"],"states":["default","hover","active","copied","focus"],"anatomy":["container","copyIcon","checkIcon"],"rules":["BTN_ICON_ONLY_ARIA_REQUIRED"]}
{"id":"datepicker","description":"日付選択コンポーネント。カレンダーポップアップ + キーボードナビ。","variants":["trigger","calendar","day-cell"],"states":["default","open","selected","today","disabled","error","hover","focus"],"stateSpecs":{"open":{"description":"カレンダー展開。calendar variant が開いた姿そのもの=差分なし。","tailwind":"","ariaChanges":"トリガーに aria-expanded=\"true\"。calendarPopup を role=\"dialog\" で表示しフォーカス移動。","htmlNote":"structural 状態。calendar variant の tailwind(absolute mt-1 ... z-20)が open の表示。default は calendarPopup を hidden で隠す。"},"selected":{"description":"選択済み日セル。day-cell 基底への overlay 差分。","tailwind":"bg-primary-500 text-white hover:bg-primary-600","ariaChanges":"当該 day セルに aria-selected=\"true\"。"},"today":{"description":"今日のマーカー。day-cell 基底への overlay 差分(選択とは独立)。","tailwind":"font-semibold ring-1 ring-inset ring-primary-300","htmlNote":"text color は持たず ring + 太字のみ=selected(bg-primary-500 text-white) と併用しても文字色が衝突しない。未選択時は基底の text 色を継承。"},"error":{"description":"不正入力。trigger 基底への overlay 差分。","tailwind":"border-red-600","ariaChanges":"トリガーに aria-invalid=\"true\" + aria-describedby でエラーメッセージ参照。"},"disabled":{"description":"操作不可。全 variant 共通。","tailwind":"opacity-50 cursor-not-allowed pointer-events-none","ariaChanges":"トリガーに disabled 属性 + aria-disabled=\"true\"。カレンダーを開けない。"}},"anatomy":["trigger","hiddenInput","calendarPopup","monthHeader","dayOfWeekHeader","dayGrid","todayButton?"],"rules":["DATEPICKER_NO_NATIVE_INPUT","DATEPICKER_NO_SHADOW_LG","DATEPICKER_Z_INDEX_20","DATEPICKER_NO_COLOR_ONLY_TODAY","DATEPICKER_KEYBOARD_NAV_REQUIRED","DATEPICKER_WEEKDAY_HEADER_REQUIRED"]}
{"id":"divider","description":"セクション間の視覚的区切り。水平 / テキスト付き / 垂直の3パターン。","variants":["horizontal","with-text","vertical"],"states":["default"],"anatomy":["line","label?","container?"],"rules":["DIVIDER_NO_DIV_BORDER_B","DIVIDER_NO_GRAY_100","DIVIDER_NO_SLATE_400_PLUS"]}
{"id":"dropdown","description":"ドロップダウンメニュー。キーボードナビゲーション対応。","variants":["basic","with-icons","with-separator"],"states":["default","open","hover","focus","disabled","destructive"],"stateSpecs":{"open":{"description":"メニュー展開。menuContainer variant が開いた姿そのもの=差分なし。","tailwind":"","ariaChanges":"triggerButton に aria-expanded=\"true\"。menuContainer を role=\"menu\" で表示。","htmlNote":"structural 状態。variant の tailwind(absolute top-full ... z-20)が open の表示。default は menuContainer を hidden で隠す。"},"destructive":{"description":"破壊的アクションの menuItem。menuItem 基底への overlay 差分。","tailwind":"text-red-700 hover:bg-red-50","htmlNote":"「削除」等の危険操作項目に適用。アイコンも text-red-600 に揃える。"},"disabled":{"description":"操作不可。全 variant 共通。","tailwind":"opacity-50 cursor-not-allowed pointer-events-none","ariaChanges":"トリガーに aria-disabled=\"true\"。開けない(aria-expanded は false のまま)。"}},"anatomy":["triggerButton","menuContainer","menuItem","leadingIcon?","separator?","menuGroupLabel?"],"rules":[]}
{"id":"empty-state","description":"データ無し時のプレースホルダー(アイコン + タイトル + 説明 + 任意のアクション)。Text + Button の compose。","webStatus":"pending","variants":["default"],"states":["default"],"anatomy":["icon?","title","description?","actionButton?"],"rules":[]}
{"id":"header","description":"画面ヘッダー。defaultは左寄せ見出し、actionsは可視タイトルなしの操作バー、centered/navigationは中央タイトル。配置・寸法・文字組みはHeaderが所有し、画面の操作内容とnavigationは利用側が渡す。","webStatus":"pending","variants":["default","actions","centered","navigation"],"states":["default"],"anatomy":["container","title","leading?","trailing?"],"rules":[]}
{"id":"icon","description":"統一アイコン primitive。name prop でグリフを選択し(グリフ集合は実装側の公開面 = assets/icons の Charcoal セット由来)、色は semantic token キー限定の prop(default ","webStatus":"pending","variants":["default"],"states":["default"],"anatomy":["glyph"],"rules":[]}
{"id":"image","description":"画像表示 primitive。aspectRatio / radius / contentFit / onError fallback を持つ。Phase1 は RN コア Image、expo-image は Phase2。","webStatus":"pending","variants":["default"],"states":["default","error"],"anatomy":["image","fallback?"],"rules":[]}
{"id":"list","description":"リストアイテム。Link / Information / Action / Toggle / Selection の6タイプ。","variants":["link","information","action"],"states":["default","hover","active","selected","focus"],"anatomy":["container","primaryText","secondaryText?","leftIcon?","leftImage?","rightIcon?","rightImage?","action?","border?"],"rules":["LIST_NO_FIXED_HEIGHT_MISMATCH","LIST_NO_COLOR_ONLY_SELECTION","LIST_NO_GESTURE_ONLY","LIST_NO_ICON_BORDER"]}
{"id":"metric","description":"数値 + 単位 + ラベルの指標表示 primitive(距離 / 時間 / 獲得標高 等の走行サマリー表示)。tabular-nums で桁揃え。sizes の height は数値テキストの想定行高(px)で、実 fontSize は実","webStatus":"pending","variants":["default"],"states":["default"],"anatomy":["value","unit?","label?"],"rules":[]}
{"id":"modal","description":"フォーカストラップとバックドロップを備えたモーダルダイアログ。","variants":["confirmation","form","alert"],"states":["default","open","closing"],"stateSpecs":{"default":{"description":"閉。DOM 上 hidden。","tailwind":"hidden","ariaChanges":"aria-hidden=\"true\"。"},"open":{"description":"表示。フォーカストラップ作動。","tailwind":"","ariaChanges":"aria-modal=\"true\"。Escape で閉じる(MODAL_ESC_CLOSE_REQUIRED)。","htmlNote":"variant tailwind(fixed inset-0 flex items-center justify-center z-50)がそのまま open の表示。open は variant 基底=差分なし。"},"closing":{"description":"閉アニメ中。完了後 hidden に戻し focus 復帰。","tailwind":"opacity-0 transition-opacity duration-150","htmlNote":"トランジション終了で default(hidden) へ。"}},"anatomy":["overlay","container","header","body","footer","closeButton"],"rules":["MODAL_FOCUS_TRAP_REQUIRED","MODAL_ESC_CLOSE_REQUIRED","MODAL_CLOSE_REQUIRED","MODAL_ROLE_DIALOG_REQUIRED","MODAL_OVERLAY_REQUIRED","MODAL_NO_NESTED"]}
{"id":"pagination","description":"ページ送りナビゲーション。w-10 h-10タップターゲット。","variants":["active","inactive","disabled"],"states":["default","active","disabled","hover","focus"],"anatomy":["navContainer","pageButton","prevButton","nextButton","ellipsis?"],"rules":["BTN_MIN_TAP_TARGET","A11Y_NAV_ARIA_LABEL_REQUIRED"]}
{"id":"progress","description":"リニアプログレスバー。aria-valuenow/min/max必須。","variants":["primary","success","indeterminate"],"states":["default","determinate","indeterminate","complete"],"anatomy":["track","fill","label?","percentage?"],"rules":["MOTION_REDUCED_MOTION_REQUIRED"]}
{"id":"radio","description":"単一選択フォームコントロール。fieldsetラッパー必須。","variants":["vertical","horizontal","card-style"],"states":["default","selected","unselected","disabled","error","focus"],"stateSpecs":{"selected":{"description":"選択済み。radioCircle 基底への overlay 差分 + selectedIndicator 表示。","tailwind":"border-primary-500","ariaChanges":"当該 <input type=\"radio\"> に checked + aria-checked=\"true\"。selectedIndicator(内側ドット bg-primary-500)を表示。"},"unselected":{"description":"未選択(radioCircle の基底状態)。default の resting と同義=差分なし。","tailwind":"","ariaChanges":"aria-checked=\"false\"。selectedIndicator は非表示。"},"error":{"description":"バリデーションエラー。radioCircle 基底への overlay 差分。","tailwind":"border-red-600","ariaChanges":"radiogroup に aria-invalid=\"true\" + aria-describedby で errorText 参照。","htmlNote":"errorText を text-red-600 で表示。selected と併用時は error の border-red-600 を優先(選択済みでもエラーなら赤枠)。"},"disabled":{"description":"操作不可。全 variant 共通。","tailwind":"opacity-50 cursor-not-allowed pointer-events-none","ariaChanges":"各 <input type=\"radio\"> に disabled + aria-disabled=\"true\"。"}},"anatomy":["radioCircle","selectedIndicator?","label","groupLabel","description?","helperText?","errorText?"],"rules":["FORM_FIELDSET_LEGEND_REQUIRED","FORM_NO_LABEL_OMIT"]}
{"id":"row","description":"子要素を横に並べる layout primitive。gap は spacing token キー限定の prop。折返し(wrap)と主軸配置(justify)を持ち、タグ列・メトリクス列・ヘッダー行の生 flexbox 手書きを置き換え","webStatus":"pending","variants":["default"],"states":["default"],"anatomy":["container"],"rules":[]}
{"id":"screen","description":"画面骨格 primitive(SafeArea + bg-page + content padding)。header slot を scroll 外に固定し、毎画面手書きされる SafeAreaView + ScrollView + ヘッ","webStatus":"pending","variants":["fixed","scroll"],"states":["default"],"anatomy":["safeArea","header?","content"],"rules":[]}
{"id":"select","description":"ドロップダウン選択。appearance-none + カスタムSVGシェブロン必須。","variants":["default","error","disabled"],"states":["default","hover","focus","error","disabled"],"anatomy":["label","wrapper","select","chevronIcon"],"rules":["FORM_SELECT_APPEARANCE_NONE","FORM_NO_LABEL_OMIT"]}
{"id":"sidebar","description":"メインナビゲーション用サイドバー。Standard / Compact / Drawer の3バリエーション。","variants":["standard","compact","drawer"],"states":["default","collapsed","drawer-open"],"anatomy":["header","nav","navItem","footer"],"rules":["SPACE_NO_NONSTANDARD_SIDEBAR_WIDTH","SPACE_NO_DARK_SIDEBAR_BG","SPACE_NO_ROUNDED_XL_NAV","SPACE_NO_LARGE_NAV_ICON","SPACE_NO_MISSING_ARIA_CURRENT","SPACE_NO_DRAWER_NO_FOCUS_TRAP","A11Y_NAV_ARIA_LABEL_REQUIRED"]}
{"id":"skeleton","description":"ローディングプレースホルダー。aria-busy=\"true\"必須。","variants":["text","card","circle"],"states":["default","loading","loaded"],"anatomy":["container","circle?","bar","srOnlyText"],"rules":["SKELETON_ARIA_BUSY_REQUIRED","SKELETON_ARIA_BUSY_RELEASE","SKELETON_BG_SLATE_200_ONLY","SKELETON_NO_SPINNER_ONLY","MOTION_REDUCED_MOTION_REQUIRED"]}
{"id":"stack","description":"子要素を縦に積む layout primitive。gap は spacing token キー限定の prop(省略時 gap なし)。画面の縦リズムを生 flexbox 手書きから置き換える(dogfood 不足-1)。","webStatus":"pending","variants":["default"],"states":["default"],"anatomy":["container"],"rules":[]}
{"id":"stepper","description":"マルチステッププロセスの進捗表示。Completed / Active / Upcoming の3状態。","variants":["horizontal","vertical"],"states":["completed","active","upcoming"],"anatomy":["container","step","indicator","label","description?","connector"],"rules":["STEPPER_NO_COLOR_ONLY_STATE","STEPPER_ARIA_CURRENT_REQUIRED","STEPPER_MIN_INDICATOR_SIZE","STEPPER_NO_DARK_CONNECTOR"]}
{"id":"surface","description":"Card / Skeleton / EmptyState の共通土台となる箱 primitive(bg / radius / elevation / padding)。melta-app では internal(未 export)。","webStatus":"pending","variants":["default"],"states":["default"],"anatomy":["container"],"rules":[]}
{"id":"table","description":"データテーブル。th scope=\"col\"必須。","variants":["basic","sortable"],"states":["default","hover","empty"],"stateSpecs":{"empty":{"description":"0件。空状態行を表示。全 variant 共通。","tailwind":"","htmlNote":"<tbody> 内に colspan 全列結合の1行で中央寄せ「データがありません」。"}},"anatomy":["wrapper","caption","th","row","td"],"rules":["TABLE_TH_SCOPE_REQUIRED","TABLE_NO_LAYOUT_TABLE"]}
{"id":"tabs","description":"コンテンツ切り替えタブ。underline(下線)/ bar(丸角バー)の2バリアント。キーボードナビ対応。","variants":["underline-active","underline-inactive","bar-active","bar-inactive"],"states":["default","active","inactive","disabled","hover","focus"],"stateSpecs":{"disabled":{"description":"操作不可。全 variant 共通。","tailwind":"opacity-50 cursor-not-allowed pointer-events-none","ariaChanges":"tab に aria-disabled=\"true\" + tabindex=\"-1\"(フォーカス・選択不可)。"}},"anatomy":["tabList","tab","tabPanel","indicator"],"rules":[]}
{"id":"tag","description":"削除可能なタグ / フィルターチップ。","variants":["basic","removable","filter-chip"],"states":["default","active","inactive","hover","focus"],"anatomy":["container","labelText","removeButton?","checkmarkIcon?"],"rules":["TAG_X_ARIA_LABEL_REQUIRED","TAG_REMOVABLE_X_REQUIRED","TAG_X_MIN_TAP_TARGET","TAG_FILTER_ARIA_SELECTED_REQUIRED","TAG_BADGE_CONFUSION"]}
{"id":"text","description":"本文・見出し・キャプションの基本テキスト primitive。fontSize variant と semantic color、heading/body で letterSpacing を切替。","webStatus":"pending","variants":["xxs","xs","sm","base","lg","xl","2xl","3xl"],"states":["default"],"anatomy":["textNode"],"rules":[]}
{"id":"textfield","description":"テキスト入力フィールド。Default / Error / Disabled / Success の4状態。","variants":["default","error","disabled","success"],"states":["default","hover","focus","error","disabled","success"],"anatomy":["label","input","helperText?","errorMessage?"],"rules":["TYPO_NO_PLACEHOLDER_ONLY","FORM_NO_LABEL_OMIT","FORM_NO_COLOR_ONLY_ERROR","FORM_NO_DISTANT_ERROR"]}
{"id":"toast","description":"一時的な通知メッセージ。4タイプ(success/error/warning/info)。","variants":["success","error","warning","info"],"states":["default","entering","visible","dismissing","hover"],"anatomy":["container","statusIcon","message","description?","closeButton","actionButton?","progressBar?"],"rules":[]}
{"id":"toggle","description":"ON/OFFスイッチコンポーネント。role=\"switch\"必須。","variants":["off","on"],"states":["off","on","hover","focus","disabled"],"stateSpecs":{"disabled":{"description":"操作不可。off/on 共通。","tailwind":"opacity-50 cursor-not-allowed pointer-events-none","ariaChanges":"disabled 属性 + aria-disabled=\"true\"。aria-checked は現状態を保持。"}},"anatomy":["track","thumb","label","description?","statusText?"],"rules":[]}
{"id":"tooltip","description":"ホバー/フォーカスで表示される補足情報。max-width: 20rem。","variants":["top","bottom","left","right"],"states":["default","visible","hidden"],"anatomy":["container","text"],"rules":[]}

Discussion

Did this work in your project? Say what you used it for and what you changed. People and their agents can both post here.

Posts are public.Sign in to post

No one has posted yet. Be the first.