# 文字化けリンク — Style Reference
> 黒の上の象牙色の目次。触れた行だけ字が崩れ、左から一文字ずつ戻る

**Theme:** dark  **Series:** PARTS 060  **World:** 架空の制作スタジオ「Studio Kōri」の目次。行は 5 本、色は象牙と灰、コバルトは 1 点。

## Concept
目次の行にカーソルが乗ると、その行の文字がランダムな字(カタカナ・漢数字・英数字・記号)に置き換わり、左から一文字ずつ正しい字に固定されていく。固定中の一文字だけコバルト色で、どこまで解読が進んだかが読める。左の読み出し(active / locked / frame)は計測値として置き、演出を言葉で説明しない。読み込み後は 1.5 秒ごとに上から順に自動で崩して見せ、カーソルが乗った時点で自動は止まる。

## Signature Technique
文字列を 1 文字ずつ配列にし、経過時間から「固定済みの文字数」を決めて、残りをランダム文字で描き直す。

- 開始から `hold`(300ms)はすべての文字がランダム。以後 `locked = floor((t − hold) / lockEvery)`(lockEvery 120ms)
- ランダム文字の描き直しは `glyphMs`(40ms)ごと。固定済みの文字は正しい字、`locked` 番目の 1 文字は `<b>` で包みコバルトに、その右はランダム
- 文字幅が揺れないよう行は `white-space: nowrap`、数字は `tabular-nums`。フォントは Noto Sans JP 300 で、字によって幅が変わるが行の高さは固定
- 全文字が固定されたら `textContent` に戻して終了。再度ホバーで最初から
- 自動デモ: `idleStart` 400ms 後から `idleEvery` 1500ms ごとに次の行を崩す。`pointerenter` / `focus` / `click` で `idle.stop = true`
- rAF 1 本で全行を更新。`visibilitychange` で停止
- reduced-motion: 崩さない(行はそのまま)。矢印の移動も CSS で止めない程度の 6px だけ

```js
const el = now - r.t0;
r.locked = clamp(Math.floor((el - P.hold) / P.lockEvery), 0, n);
if (now - r.last >= P.glyphMs) {
  let html = '';
  for (let i = 0; i < n; i++) html += i < r.locked ? chars[i] : (i === r.locked ? '<b>' + rnd() + '</b>' : rnd());
  w.innerHTML = html;
}
```

## Color Palette
| Token | HEX | Role |
|---|---|---|
| --onyx | #121219 | 地色 |
| --card | #1A1A24 | 予備の面 |
| --ivory | #F2EFE6 | 本文、行の文字 |
| --ash | #8B8B97 | 番号と英語ラベル。読み出しにも |
| --hair | rgba(242,239,230,.12) | 行の罫線 |
| --cobalt | #5266EB | 固定中の 1 文字、focus、読み出しの数 |

## Typography
- 行: Noto Sans JP 300 `clamp(28px, 4.6vw, 64px)` / line-height 1.15 / tracking .02em
- 見出し(左): Noto Sans JP 500 `clamp(17px, 1.5vw, 21px)` / line-height 1.6 / tracking .01em、本文 400 `clamp(13px, 1.05vw, 15px)`、最大幅 26em
- 番号・ラベル: JetBrains Mono 12px、tracking .08em。読み出し: 12px、tracking .04em、`tabular-nums`。上の帯 12px(640px 以下で 11px)、下のタグ 11px
- ランダム文字の候補はカタカナと漢数字を多めにし、崩れても日本語の行に見えるようにする

## Spacing & Layout
- 2 カラム grid `1fr / 2fr`、gap `clamp(24px, 6vw, 96px)`、上下 6vh
- 左の説明: 見出しの下 10px に本文、その下 28px に読み出し(2 列 grid、gap 4px / 18px)
- 行: `grid 3.2em / 1fr / auto`、gap 18px、縦 padding `clamp(14px, 2.2vh, 24px)`、上下に 1px の罫
- 画面余白: 横 `clamp(20px, 5vw, 72px)`、上 `clamp(20px, 3vw, 40px)`、下 `max(18px, safe-area)`
- 860px 以下: 1 カラム(gap 28px)、行は `2.4em / 1fr`(gap 12px)で英語ラベルと矢印を消す。読み出しは横に詰める
- 640px 以下: 右上の案内を消し、左右余白 18px、タグを左揃え

## Motion
- 崩れ: hold 300ms → 120ms に 1 文字固定。5 文字で 0.9 秒
- 矢印: hover で 6px 右へ、`cubic-bezier(.2,.8,.2,1)` 350ms
- 自動デモ 1.5 秒周期。操作で停止
- reduced-motion: 崩れを止め、行は静止したまま

## Components
- 上の帯: 名前 / 区画名、右に `hover to decode`
- 左の説明: 見出し 1 本、本文 1〜2 文、読み出し 3 行
- 行(リンク): 番号 / 文字 / 英語ラベル + 矢印。focus-visible で番号がコバルトに
- 右下のタグ: `VALE / PARTS 060 / 文字化けリンク` と操作の 1 行

## Do / Don't
Do
- 固定中の 1 文字だけに色を付ける
- 候補文字は表示言語に合わせる(日本語の行ならカタカナ・漢字)
- 行の高さを固定し、崩れている間にレイアウトを動かさない
- 自動デモは操作が入った瞬間に止める

Don't
- 全行を同時に崩さない
- 1 文字あたり 60ms より速く固定しない(読めない)
- 色を 2 色以上使わない
- 行の幅に合わせて文字を縮めない

## References
- Mercury(Alpine banking at blue hour): 近黒に象牙の文字、コバルト 1 点だけを主要動作に使う配分。地色を #121219、コバルトを「解読中の 1 文字」に移した
- Krea(noir gallery at midnight): 黒の上の大きな display 文字と、白塗り / ゴースト pill 以外に色を入れない規律。display を weight 300 の明るい字に変え、黒は純黒を避けて青みを足した

## Usage
1. HTML: `<a data-text="正しい文字"><span class="n">01</span><span class="w">正しい文字</span><span class="m">label</span></a>` を行の数だけ置く。`.n` `.m` は不要なら消す
2. CSS: `nav a`、`nav a .w`、`nav a .w b` の 3 ルールを移植する(`.w b` が固定中の 1 文字の色)
3. JS: `<script>` ブロックを移植し、`P` で調整する。読み出し(`#rAct` など)が無いなら該当行を消す
4. 自動デモが不要なら `idle` のブロックを消す

| パラメータ | 既定 | 意味 |
|---|---|---|
| hold | 300 | 全文字がランダムな時間 (ms) |
| lockEvery | 120 | 1 文字固定にかける時間 (ms) |
| glyphMs | 40 | ランダム文字の描き直し間隔 (ms) |
| idleStart / idleEvery | 400 / 1500 | 自動デモの開始と周期 (ms) |
| pool | 文字列 | ランダム文字の候補 |

注意: `innerHTML` を書くので、`data-text` にはタグを含めない。英字の行では `pool` を英数字だけにする。
