No. 19

プレミアム不動産 Premium Real Estate

分譲マンションの落ち着いた高級感を、明朝と大きな写真、低彩度の配色で組む。金は塗らず細線と点だけに使い、間取り・専有面積・価格帯・徒歩分数・来場予約や資料請求といった物件サイトの実務を写真と同じ重さで扱う。左スティッキーレール+右スクロールのsplit-screenに、全幅写真+帯1本のヒーローを組み合わせる。

プレミアム不動産のスクリーンショット

仕様

typographymincho-modern
color-strategylow-saturation
densityairy
layoutsplit-screen
ornamentphoto-dominant
motionsubtle
moodluxury / serene / trust
industryreal-estate
架空企業架空・分譲マンション「クレフ代々木上原」(東京都渋谷区、総戸数48戸、1LDK〜3LDK、小田急線・東京メトロ千代田線「代々木上原」駅徒歩5分)
license商用利用可・改変可・クレジット不要

検証記録

verified_at: 2026-07-16

公式パイプライン検証(Claude Code / sonnet subagent): DESIGN.md+tokens.cssのみを別セッションに渡し、別ビジネス業種=デザイン注文住宅『余白建築』で再生成(verification/custom-home)。judge5ラウンド: reveal詳細度バグ(html.js-motion側が.is-visibleを上回りopacity:0固定)を:where()で解消、さらにモバイル横スクロールの実バグ(.shellのflex-column時にalign-items未リセットで.plan-table 720pxが.mainを押し広げ本文切れ)を指揮官がalign-items:stretchで修正→scrollWidth 760→375をブラウザ実測で確認→r2で合格。Zen Old Mincho×Cormorant Garamond・温白/墨茶/低彩度金・split-screen左レール固定・プラン表の横罫線のみ・金は面でなく線と点に限定まで業種替えで一致。写真はWikimedia CommonsのCC0のみ(検証側は実写真代替の自作SVG線画で型を再現)

DESIGN.md

DESIGN.mdtokens.css

https://3pt.co.jp/design-library/md/realestate-premium/DESIGN.md

# DESIGN.md — プレミアム不動産 / realestate-premium

> **使い方**: このファイルをプロジェクトに置き、AIに
> 「DESIGN.md に従って◯◯のサイトを作って」と指示してください。
> ライセンス: 商用利用可・改変可・クレジット不要(AIっぽくないデザイン見本帳 / サードパーティートラスト)

## 1. コンセプト

分譲マンション・邸宅の「落ち着いた高級感」を、大きな写真と品のある明朝、
低彩度の配色で組む。ただし余白と静けさに逃げず、物件サイトとしての実務
(間取り・専有面積・価格帯・立地・来場予約/資料請求のCV導線)を必ず備える。
「高級=黒地に金グラデ+全部大文字」の手癖を避け、金は塗らず**細線と点**でだけ使う。

**キーワード**: 静穏 / 邸宅 / 実務 / 上質 / 写真主役
**この見た目が向く場面**: 分譲マンション・注文住宅・高級賃貸・別荘地開発・
不動産デベロッパーのブランドサイト

## 2. タイポグラフィ

- 和文見出し: Zen Old Mincho / ウェイト 500(大見出しは500、価格・型番など
  強調したい語のみ600を使ってよい。本文には600を使わない)
- 和文本文: Zen Old Mincho / ウェイト 400 / サイズ 16px / 行間 1.95 / 字間 0.03em
- 欧文・数字: Cormorant Garamond(コンセプト英文・専有面積や価格の数字部分・
  節番号に使う。本文にイタリックで添える程度に留め、地の文の代替にしない。
  **Inter に置換しない**)
- 見出しスケール: h1(物件名) clamp(34px, 5vw, 56px) / h2(節見出し)
  clamp(24px, 3vw, 32px) / h3(table見出し・カード見出し) 18px /
  本文 16px / キャプション・ラベル 12.5px
- 特記: 英字ラベル(節番号・区分名)は 11.5〜12px・字間 0.16〜0.22em・
  大文字。**コンセプト見出し(h2「コンセプト」節のみ)に縦書き
  (`writing-mode: vertical-rl`)を使う。** 他の節見出しは横書きのまま
  (縦書きの多用は誌面性が強くなりすぎるため、コンセプト1箇所に限定する)。
  価格・専有面積などの数字は Cormorant Garamond で組み、桁の召喚力を出す

## 3. カラー

**low-saturation。純白・純黒・ビビッドカラーを使わない。**

| 役割 | 値 | 使用比率の目安 |
|---|---|---|
| 地(温白・ベース) | #f6f4ef | 60% |
| 地(節替え) | #efece3 | — |
| 墨茶(見出し・本文・強い要素) | #2a2723 | 30% |
| 弱文字(説明文・キャプション) | #6b6660 | — |
| 石グレー(罫線・境界・大きい要素の装飾のみ) | #8d8983 | — |
| くすみ金茶(アクセント) | #9c8961 | 5%以下 |
| 罫線(ヘアライン) | #ddd6c6 | — |

- 配色ルール: **くすみ金茶は「線」と「点」と「大きな文字」にのみ使う。**
  許される用法は ①節番号の細い下線 ②区切りの短い罫(幅16〜32px程度)
  ③価格・専有面積などの大きな数字(24px以上) ④予約状況ドットや必須項目
  マークなど、非文字の小さな点マーカー
  の4つ。**金を面(背景・カード・バッジの塗り)に使わない。金にグラデ・
  グロー・メタリック表現をかけない。金を本文サイズの文字色として使わない
  (文字自体は墨茶にし、金は文字に添える点や罫にとどめる)。**
- **コントラスト実測(両方向。全て背景 or 前景として使う色の組み合わせ)**:
  - `#2a2723` on `#f6f4ef` = **13.52:1**(本文・見出し、AA/AAA余裕)
  - `#2a2723` on `#efece3` = **12.58:1**(節替え背景でも同様に使える)
  - `#6b6660` on `#f6f4ef` = **5.17:1**(弱文字・キャプション、AA適合。
    これより明るいグレーを弱文字の既定色にしない)
  - `#6b6660` on `#efece3` = **4.81:1**(節替え背景でもAA適合)
  - `#9c8961`(金) on `#f6f4ef` = **3.10:1** / on `#efece3` = **2.88:1**
    — **AA本文基準(4.5:1)を満たさない。金を本文サイズ・小ラベルの文字色に
    使わない。使ってよいのは大きな数字(24px以上、AA-large基準3:1を満たす)
    と、文字ではない線・点のみ**
  - **大きな数字(`.num`、34px)に金を文字色として使う場合は、`--color-accent`
    をそのまま使わず、彩度・明度を落とした専用トークン `--color-accent-text:
    #7f6a40` を使う。** `#7f6a40` on `#f6f4ef` = **4.73:1**(AA-large基準
    3:1に対し余裕あり。`#9c8961` の 3.10:1 はぎりぎりでマージンがないため、
    このように文字用途では必ず一段暗い金を使う。線・罫・点などの非文字装飾は
    引き続き `--color-accent`(#9c8961)のままでよい)
  - `#8d8983`(石グレー) on `#f6f4ef` = **3.16:1** — 同様に本文色に
    使わない。罫線・大きな装飾要素の色として使う
  - `#f6f4ef`(温白) on `#2a2723`(墨茶地) = **13.52:1**(主ボタン・
    反転部の文字色として使用可)
  - `#9c8961`(金) on `#2a2723`(墨茶地) = **4.36:1** — AA本文基準に
    僅かに届かない。**暗い地の上でも金を本文サイズの文字に使わず、
    ホバー時の線・小さな数字ラベル(18px以上)に限定する**
- 青・紫・緑・信号色を一切追加しない。純白 #ffffff・純黒 #000000 を使わない

## 4. レイアウト・余白

- コンテンツ最大幅: 1280px(本文カラムは 640px 程度に絞る節もある)
- **split-screen** を骨格にする。ヘッダー直下から、左に幅 30%(最小280px)の
  `position: sticky` レール(物件名ロゴ・節ナビ・来場予約への短い導線)を置き、
  右70%が本文としてスクロールする。左右の境は 1px の罫線 `--color-line`
- **ヒーローは中央寄せの定型にしない。** 全幅裁ち落としの建築写真1枚を置き、
  写真下端に**不透明の墨茶帯**を敷いて「物件名(h1)+所在地・総戸数の短い
  1行+来場予約ボタン1つ」だけを乗せる。ボタンを2つ並べない。左サイドの
  スティッキーレールはヒーロー区間では非表示にし、写真だけを全画面に見せる
  (次節から左レールが現れる)
- セクション間余白: 上下 120px 基準(airy)。要素間は 8px の倍数
- 各節の頭に「節番号(Cormorant、例: 01)+金の短い罫(24px)+英字ラベル+
  和文見出し」を置く。コンセプト節のみ見出しを縦書きにする
- プラン表・仕様リストは**罫線区切り**で組む。角丸カード+影の3カラムに
  絶対に流用しない

## 5. コンポーネントの質感

- ヘッダー: ヒーロー区間は透明地・白文字、スクロールで不透明な `--color-bg`
  地・墨茶文字に切り替わる(`backdrop-filter` は使わず不透明背景に変える)。
  ヘッダーは `position: fixed` かつ `height: var(--header-h)` の固定高さを持ち、
  z-indexは左レールより高い値にする。**左スティッキーレールの `top` は必ず
  `var(--header-h)` を使い、`top: 0` にしてはならない**(レール上端の
  ブランド名・節ナビが不透明化後のヘッダーに恒久的に隠れる実装バグを防ぐため)。
- 左スティッキーレール: 地色 `--color-bg-alt`、物件名(小さめ、明朝)と
  節リンク(縦に並べる。現在地の節は金の短い下線が入る。他は下線なし、
  ホバーで文字が墨茶から金に変わるのではなく**字間が広がる**)。
  一番下に小さく「来場予約はこちら →」のテキストリンクを常設
- 角丸: 0px(すべて直角)/ 影: 使わない(`box-shadow` 禁止)/
  境界線: 1px solid `--color-line`。強調したい罫のみ 1px の金 `--color-accent`
- ボタン: 主ボタン(来場予約)は**墨茶地+温白文字**、直角、ホバーで
  背景がわずかに明るくなる(`#2a2723`→`#3a352f`、0.2s)。副ボタン
  (資料請求)は透明地+1px墨茶罫線+墨茶文字、ホバーで罫線が金に変わる。
  **ヒーロー内は主ボタン1つのみ**。フォーム送信ボタンも同じ主ボタン様式。
  **ただしヒーロー帯(背景が既に墨茶)の上では主ボタンを反転させ、
  温白地+墨茶文字にする**(地と同色のボタンは見えなくなるため。
  `.hero-band .btn-primary` で上書きする。§9コード例参照)
- プラン表(間取りタイプ): `<table>` を使い、横罫線 `--color-line` のみで
  区切る(縦罫線は引かない)。タイプ名は明朝・専有面積と価格帯は
  Cormorant Garamondの数字で右寄せに揃える。価格帯の数字の地色は墨茶
  (`--color-ink`)とし、金は数字の直上に置く幅24px・高さ1pxの短い罫
  (§3②の用法)としてのみ使う。金を価格の文字色として使わない
- 仕様リスト: アイコンの代わりに「番号(Cormorant)+項目名+説明」を
  横罫線で1行ずつ区切る。角丸カードにしない
- カード的要素: 写真+短いキャプションの組(例: 設備写真)は面や影で
  囲わず、写真の下に罫線1本+キャプションのみ
- フォーム要素(資料請求・来場予約): input/textarea は地色 `--color-bg`
  背景・下線1px `--color-line` のみ(囲み枠を作らない)・角丸0、
  フォーカスで下線が金 `--color-accent` に変わる。ラベルは上に12px・
  弱文字色で常時表示(placeholder依存にしない)。送信前に同意チェック
  ボックスを1つ置く(プライバシーポリシーへの同意、実務感を出す)
- 画像の扱い: 全写真に統一トーンフィルタ(§9)を適用。裁ち落とし・
  角丸なし。写真に文字を乗せる場合は不透明の墨茶帯のみ(半透明の
  グラデーションスクリムを使わない)
- アクセント(金)の適用範囲: §3の4用法に厳密に限定する

## 6. モーション

- 量: subtle
- **可視性はJSに依存させない(progressive enhancement)。** 節の登場演出の
  「隠れて→現れる」状態は、`<html>` に `js-motion` クラスが付いた場合のみ
  CSSで有効化する(`document.documentElement.classList.add('js-motion')`
  を `<head>` の先頭で同期実行)。このクラスが付かない限り(JS無効・
  ブロック・エラー時)、対象要素は常に `opacity: 1` の可視状態がデフォルト。
  本文・表・フォームを演出のために人質に取らない。**`.hero-photo` /
  `.hero-band` も例外なくこの原則に従う**(tier-B reviseで、この2要素だけ
  「デフォルトopacity:0・is-visible付与はJSのみ」という旧パターンが残り、
  JS無効時にヒーロー写真と価格帯が恒久的に見えなくなる実バグが見つかった。
  §9のヒーローCSS例のとおり修正済み)
- **非表示側のセレクタは必ず `:where(html.js-motion) .xxx` の形で書き、
  `html.js-motion .xxx` のように :where() なしで書かない。** 後者は型セレクタ
  `html` の分だけ詳細度が上がり、`.xxx.is-visible` を上回って opacity:0 が
  固定される(§9のコメント参照。tier-B reviseで発見・修正)
- 使う動き: 節がスクロールで視界に入ると opacity 0→1・translateY→0。
  **役割で速さと移動量を変える**(主役=見出し・写真・表・フォームは
  `.reveal-primary` で 0.85〜1s・translateY 22〜24px・ゆるやかな
  easing(`cubic-bezier(0.16,1,0.3,1)`)でゆっくり大きく。脇役=ラベル・
  本文・リスト項目は `.reveal` で 0.4〜0.5s・translateY 10px と短く小さく。
  リスト項目はさらに 60msずつ階段状にずらす)。ヒーロー写真は初回のみ
  1.4s かけて scale(1.05)→scale(1) のゆっくりしたズームアウト+フェード
  (`window.addEventListener('load', …)` と `setTimeout` のみで起動。
  `requestAnimationFrame` は使わない)
- **IntersectionObserverの取りこぼしに対するフォールバック(必須)。**
  マウスホイールの連続大ティック・スクロールバードラッグ・Endキー等の
  高速/瞬間スクロールでは、要素が一度もビューポートと交差した状態を
  観測されないまま通過し、IOが発火せず `opacity: 0` に恒久固定される
  バグが起こり得る(実機検証で37要素中33要素が非表示のまま固定される
  再現あり)。対策として、`scroll`/`resize`/`load` のたびに(100ms
  デバウンス)、`getBoundingClientRect().top < window.innerHeight`
  (=現在ビューポート内、またはすでに上端を通過済み)である未reveal
  要素を強制的に `is-visible` 化する関数を必ず併走させる。IOは初回の
  「動きながら現れる」演出のためだけに使い、可視性の最終保証はしない
- ヘッダーの不透明化は 0.3s。左レールの現在節インジケータ(金の下線)は
  0.25s で移動する
- 使わない動き: パララックス、自動カルーセル、数字のカウントアップ、
  マーキー、バウンス、均一0.6秒の一律フェード(全要素が同じ速さ・
  同じ移動量で現れる均一フェードは§Aの手癖に該当するため、上記の
  主役/脇役の速さ・移動量の差を必ず付ける)
- `prefers-reduced-motion: reduce` 時は全ての transition/animation を止め、
  要素は最終状態で即表示する。リセット対象には `.hero-photo` / `.hero-band`
  を含む全reveal系クラス(`.reveal` / `.reveal-primary` / `.section-label` /
  `h2.section-head`)を漏れなく列挙すること(§9コード例参照)

## 7. 写真・イラスト・図版

- 写真が主役(`ornament: photo-dominant`)。4点、Wikimedia Commonsの
  CC0 / パブリックドメインのみを使用。被写体は「建築外観・緑に包まれた
  アプローチ・石材の質感・木材の質感」。人物の顔アップは使わない
- 全写真に同一のトーン統一フィルタ `saturate(0.85) contrast(1.02)
  brightness(1.0)` を適用する(§9)。裁ち落とし・角丸なし
- ロケーション節は実写真に加え、周辺施設・徒歩分数を示す**簡易な線画の
  概念図(自作インラインSVG、駅・物件・主要施設を線と円で示す模式図)**
  を1点使ってよい。写実的な地図サービスの模倣(道路網の精密な再現、
  ピン留めアイコンの多用)はしない

## 8. 禁止事項(must not)

- Inter / Roboto / Arial / Noto Sans を使わない(Zen Old Mincho /
  Cormorant Garamond で組む)
- グラデーションを一切使わない(背景・文字・ボタン・罫すべて)。
  `box-shadow` を使わない。border-radius は常に 0
- **金(くすみ金茶)を面(背景・カード・バッジ)に塗らない。** 金に
  グラデーション・グロー・メタリック表現をかけない。金を本文サイズの
  文字色として使わない(§3のコントラスト実測に従う。線・点・大きな
  数字のみに限定)
- 純白 #ffffff・純黒 #000000を使わない。青・紫・緑・信号色を追加しない
- **「高級=黒背景+金グラデ+セリフ全部大文字」を作らない。** 地は
  必ず温白 `#f6f4ef` を基調にする(暗い節替えを作る場合も #17130f 系の
  漆黒にはせず、`--color-bg-alt` の範囲に留める)
- 中央寄せの定型ヒーロー(特大見出し+サブコピー+ボタン2つ)を作らない。
  ヒーローの主ボタンは1つのみ
- 物件情報を省いて雰囲気だけで構成しない。**間取りタイプ・専有面積・
  価格帯・最寄り駅からの徒歩分数・総戸数を必ず数値で明記する**
- 「アイコン+見出し+説明」の角丸カード×3列を機能紹介・設備紹介に
  使わない(罫線区切りのリスト/表で組む)
- 絵文字・既製アイコンセットをアイコンに使わない(線画が必要な場合は
  自作インラインSVGのみ)
- 全要素を同じ0.6秒の均一フェードで登場させない(§6の速度差を守る)
- スクロール演出用の `opacity: 0` をCSSのデフォルト状態にしない。
  `js-motion` クラス(JS到達時のみ付与)でスコープし、かつIOの取りこぼしに
  備えたフォールバック強制表示(§6)を必ず実装する。「JSが発火しなければ
  本文が永久に見えない」設計を作らない(`.hero-photo` / `.hero-band` も含め
  例外を作らない)
- 非表示側のスコープ用セレクタを `:where()` なしの子孫セレクタ
  (例: `html.js-motion .reveal`)で書かない。型セレクタ`html`の分だけ
  詳細度が上がり `.reveal.is-visible` を上回って opacity:0 に固定される
  (§6・§9参照)
- グラスモーフィズム(半透明+`backdrop-filter: blur`)を使わない
- 写真上の文字に半透明グラデーションのスクリムを使わない(不透明の
  墨茶帯のみ、§5・§9)
- stickyレールの `top` をヘッダー高さの補正なしに `0` にしない(fixedヘッダーが
  レール上端のブランド名・ナビを恒久的に覆い隠す構造バグを生むため。§9の
  コード例通り `var(--header-h)` を使うこと)

## 9. 実装ノート

```css
/* tokens.css — この変数セットをそのまま使うこと */
:root {
  --color-bg: #f6f4ef;        /* 温白ベース */
  --color-bg-alt: #efece3;    /* 節替え */
  --color-ink: #2a2723;       /* 見出し・本文・強い要素(墨茶。純黒にしない) */
  --color-text: #2a2723;
  --color-text-weak: #6b6660; /* 弱文字。#f6f4efで5.17:1・#efece3で4.81:1 */
  --color-stone: #8d8983;     /* 石グレー。罫線・大きい装飾要素のみ(本文色にしない) */
  --color-accent: #9c8961;    /* くすみ金茶。線・点のみ(文字色にしない。§3参照) */
  --color-accent-text: #7f6a40; /* 金を大きな数字(24px以上)の文字色に使う場合専用。#f6f4efで4.73:1 */
  --color-line: #ddd6c6;      /* ヘアライン罫 */

  /* 変数には総称ファミリ(serif)を含めないこと。フォールバック連結が壊れる */
  --font-heading: "Zen Old Mincho";
  --font-body: "Zen Old Mincho";
  --font-latin: "Cormorant Garamond";

  --max-width: 1280px;
  --measure: 640px;
  --radius: 0;
  --rail-width: 30%;
  --header-h: 64px; /* ヘッダーの実高さ。stickyレールのtopオフセット計算に使う */

  --photo-filter: saturate(0.85) contrast(1.02) brightness(1.0);
}
```

- フォント読み込み:
  `https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;0,500;0,600;1,400;1,500&family=Zen+Old+Mincho:wght@400;500;600;700&display=swap`
- 本文の font-family は `var(--font-latin), var(--font-body), serif` の順に
  指定する(英数字が自動で Cormorant Garamond になる)

**写真のトーン統一(全写真に必ず適用。裁ち落とし・角丸なし):**
```css
.ph, .hero-photo img { filter: var(--photo-filter); object-fit: cover; border-radius: 0; }
```

**split-screenの骨格(左レールsticky・右がスクロール本文。ヒーローは右カラム内で全幅に抜く):**
```css
.site-header { position: fixed; top: 0; left: 0; right: 0; height: var(--header-h); z-index: 40; /* または相応の値 */ }
.shell { display: flex; align-items: flex-start; }
.rail {
  width: var(--rail-width); min-width: 280px;
  position: sticky; top: var(--header-h); height: calc(100vh - var(--header-h));
  background: var(--color-bg-alt);
  border-right: 1px solid var(--color-line);
  display: flex; flex-direction: column; justify-content: space-between;
  padding: 40px 32px;
}
.main { flex: 1; min-width: 0; }
@media (max-width: 900px) {
  .shell { flex-direction: column; }
  .rail { position: static; width: 100%; height: auto; }
}
```

**ヒーロー(全幅写真+下端の不透明帯+ボタン1つ。中央寄せ定型にしない):**
```html
<section class="hero">
  <img class="hero-photo" src="…" alt="緑のアプローチに包まれたクレフ代々木上原のエントランス外観">
  <div class="hero-band">
    <p class="hero-eyebrow">01 — CREF YOYOGI-UEHARA</p>
    <h1 class="hero-title">クレフ代々木上原</h1>
    <p class="hero-meta">東京都渋谷区 / 小田急線・千代田線「代々木上原」駅 徒歩5分 / 総戸数48戸</p>
    <a class="btn-primary" href="#reserve">モデルルーム来場予約</a>
  </div>
</section>
```
```css
.hero { position: relative; height: 100vh; min-height: 560px; overflow: hidden; }
/* .reveal系と同じ理由でデフォルトは常に可視。js-motion配下でのみ初期非表示にする
   (§6・§9「節の登場」参照。ここを .reveal 系と揃え忘れると、JS無効/失敗時に
   ヒーロー写真と価格帯が恒久的に見えなくなる事故が起こる) */
.hero-photo { width: 100%; height: 100%; object-fit: cover; filter: var(--photo-filter); opacity: 1; transform: none; }
:where(html.js-motion) .hero-photo { opacity: 0; transform: scale(1.08); }
.hero-photo.is-visible { opacity: 1; transform: scale(1); }
.hero-band {
  position: absolute; left: 0; right: 0; bottom: 0;
  background: var(--color-ink);   /* 不透明。半透明グラデにしない */
  color: var(--color-bg);
  padding: 32px clamp(20px, 5vw, 64px) 40px;
  opacity: 1; transform: none;
}
:where(html.js-motion) .hero-band { opacity: 0; transform: translateY(16px); }
.hero-band.is-visible { opacity: 1; transform: translateY(0); }
.hero-title { font-family: var(--font-heading), serif; font-weight: 500; font-size: clamp(34px, 5vw, 56px); }
/* var(--color-bg) on var(--color-ink) = 13.52:1。写真の上でも常に高コントラストを確保 */

/* ヒーロー帯の地が墨茶のため、主ボタンはこの節だけ反転させる(地と同色で消えるのを防ぐ) */
.hero-band .btn-primary { background: var(--color-bg); color: var(--color-ink); border-color: var(--color-bg); }
.hero-band .btn-primary:hover { background: #e9e4d8; border-color: #e9e4d8; }
```

**コンセプト見出しの縦書き(この1箇所のみに限定):**
```css
.concept-heading {
  writing-mode: vertical-rl; text-orientation: mixed;
  font-family: var(--font-heading), serif; font-weight: 500;
  font-size: clamp(28px, 4vw, 40px); letter-spacing: 0.14em;
}
```

**プラン表(縦罫線なし・横罫線のみ。金は価格の数字の上の短い罫にだけ):**
```css
.plan-table { width: 100%; border-collapse: collapse; }
.plan-table th, .plan-table td { padding: 18px 12px; border-bottom: 1px solid var(--color-line); text-align: left; }
.plan-table .num { font-family: var(--font-latin), serif; text-align: right; }
.plan-table .price { color: var(--color-ink); font-family: var(--font-latin), serif; font-size: 22px; font-weight: 600; }
.plan-table .price .price-rule { display: block; width: 24px; height: 1px; background: var(--color-accent); margin: 0 0 8px auto; }
/* 価格の地文字は墨茶(13.52:1)。金は数字の直上の短い罫(幅24px、§3②の用法・非文字の
   装飾なので3.10:1でWCAG非テキストコントラスト基準を満たす)としてのみ使い、文字色にしない */
```

**必須マーク(フォームラベル。金を文字色にせず、墨茶文字+金の小さな点に限定):**
```css
.form-field label .req { color: var(--color-ink); margin-left: 6px; font-weight: 600; }
.form-field label .req::before {
  content: ''; display: inline-block; width: 4px; height: 4px;
  background: var(--color-accent); margin-right: 4px; vertical-align: 1px;
}
/* 「必須」の文字は墨茶(13.52:1)。金は文字の前に置く4px角の点のみ(§3④に準じる用法) */
```

**節の登場(役割ごとに速さ/移動量を変える。可視性はJS非依存=js-motionクラスでスコープし、
IOの取りこぼしをフォールバックで必ず救済する。rAFは使わずsetTimeout/IntersectionObserverのみ):**
```html
<head>
<script>document.documentElement.classList.add('js-motion');</script>
```
```css
/* デフォルトは常に可視。js-motion配下でのみ「隠れて→現れる」演出を持つ */
.reveal, .reveal-primary { opacity: 1; transform: none; }
/*
  詳細度に関する重要な注意(tier-B reviseで発見した実バグ): 非表示側は必ず
  :where(html.js-motion) でラップすること。`html.js-motion .section-label` のように
  :where() なしで書くと、詳細度は 型セレクタ`html`1つ+クラス2つ=(0,2,1)になる。
  一方 `.section-label.is-visible` はクラス2つのみ=(0,2,0)。CSS詳細度の比較は
  (インラインstyle, ID数, クラス/属性/疑似クラス数, 型/擬似要素数) の順で行われるため、
  クラス数が同数(2=2)の場合は型セレクタの有無で決着し、(0,2,1) > (0,2,0) となって
  非表示側が勝ってしまい、`is-visible` を付与しても opacity:1 に戻らず本文が恒久的に
  見えなくなる(実機検証で37要素中33要素が固定表示のまま)。:where() は中身の詳細度を
  常にゼロにするため、非表示側を (0,1,0) まで下げれば `.xxx.is-visible`(0,2,0)が
  常に上回る。`.hero-photo` / `.hero-band` も含め、「JS到達時のみ非表示にする」
  全クラスにこの :where() パターンを例外なく適用すること
*/
:where(html.js-motion) .section-label { opacity: 0; transform: translateY(10px); transition: opacity .5s ease, transform .5s ease; }
:where(html.js-motion) h2.section-head { opacity: 0; transform: translateY(22px); transition: opacity 1s cubic-bezier(.16,1,.3,1) .12s, transform 1s cubic-bezier(.16,1,.3,1) .12s; }
:where(html.js-motion) .reveal { opacity: 0; transform: translateY(10px); transition: opacity .4s ease, transform .4s ease; } /* 脇役: ラベル・本文・リスト項目 */
:where(html.js-motion) .reveal-primary { opacity: 0; transform: translateY(24px); transition: opacity .85s cubic-bezier(.16,1,.3,1), transform .85s cubic-bezier(.16,1,.3,1); } /* 主役: 見出し・写真・表・フォーム */
.section-label.is-visible, h2.section-head.is-visible, .reveal.is-visible, .reveal-primary.is-visible { opacity: 1; transform: translateY(0); }
```
```js
window.addEventListener('load', function () {
  setTimeout(function () {
    document.querySelector('.hero-photo').classList.add('is-zoomed-out');
    document.querySelector('.hero-band').classList.add('is-visible');
  }, 80);
});

var revealTargets = document.querySelectorAll('.reveal, .reveal-primary, .section-label, h2.section-head');
var io = new IntersectionObserver(function (entries) {
  entries.forEach(function (e) {
    if (e.isIntersecting) { e.target.classList.add('is-visible'); io.unobserve(e.target); }
  });
}, { threshold: 0.12, rootMargin: '200px 0px -8% 0px' });
revealTargets.forEach(function (el, i) {
  var group = el.closest('.spec-item, .loc-access-item, .loc-facility-item');
  if (group) { el.style.transitionDelay = (i % 8) * 60 + 'ms'; }
  io.observe(el);
});

/* フォールバック救済: 高速/瞬間スクロールでIOが交差を観測できず opacity:0 のまま
   固定される事故を防ぐ。scroll/resize/load のたびに、ビューポート上端に到達済み
   (=見えている、または通過済み)の未reveal要素を強制的にis-visible化する */
function revealPassedElements() {
  var vh = window.innerHeight;
  revealTargets.forEach(function (el) {
    if (el.classList.contains('is-visible')) { return; }
    if (el.getBoundingClientRect().top < vh) { el.classList.add('is-visible'); io.unobserve(el); }
  });
}
var revealFallbackTimer = null;
function scheduleRevealFallback() {
  if (revealFallbackTimer) { clearTimeout(revealFallbackTimer); }
  revealFallbackTimer = setTimeout(revealPassedElements, 100);
}
window.addEventListener('scroll', scheduleRevealFallback, { passive: true });
window.addEventListener('resize', scheduleRevealFallback, { passive: true });
window.addEventListener('load', revealPassedElements);
revealPassedElements();
```
```css
/* prefers-reduced-motion: リセット対象は .hero-photo / .hero-band を含む
   reveal系クラス全部を漏れなく列挙する(1つでも抜けると、その要素だけ
   OSのモーション削減設定を無視して transition したままになる) */
@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
  .hero-photo, .hero-band, .reveal, .reveal-primary, .section-label, h2.section-head {
    opacity: 1 !important; transform: none !important;
  }
}
```

- モバイル(900px以下): 左レールは静的配置に戻し(`position: static`)、
  ヒーロー帯の情報は縦積みのまま維持する。プラン表は横スクロール
  `overflow-x: auto` の1つのテーブルのまま維持し、カードへの変形はしない
- `prefers-reduced-motion: reduce` では全 transition/animation を `none` にし、
  最終状態で表示する