<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0" xml:lang="ja">
<channel>
<title>イベント情報</title>
<link>http://plaza-r.co.jp/event/</link>
<atom:link href="http://plaza-r.co.jp/event/rss2.xml" rel="self" type="application/rss+xml" />
<language>ja</language>
<copyright>Copyright (C) 2026 イベント情報 All rights reserved.</copyright>
<lastBuildDate>Mon, 17 Aug 2026 18:15:08 +0900</lastBuildDate>
<generator>a-blog cms</generator>
<docs>http://blogs.law.harvard.edu/tech/rss</docs>
<item>
<dc:creator>HP管理者</dc:creator>
<title>LIXILショールーム久留米にて開催</title>
<link>http://plaza-r.co.jp/event/kurume/lixil-kurume.html</link>
<description><![CDATA[















































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">相談会特典</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">5月23日（土）〜24日（日）にLIXILショールーム久留米にてリフォーム＋新築大相談会を開催します。<br />
リフォーム・新築をお考えの皆様、お見積やご相談は無料です。<br />
ホームページまたはお電話にてご予約のうえ、ご来場ください。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02">開催場所</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">ご相談やお見積り、ご成約いただいた方全員にプレゼントをご用意しております。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">LIXILショールーム久留米</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">施工事例パネル大公開</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">〒839-0809 福岡県久留米市東合川3-19-32</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">実際にリフォームや新築をさせていただいた物件を写真にコメントを添えて一挙大公開いたします。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02">開催期間</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">相談コーナー開催</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">5月23日（土）〜24日（日）<br />
10時〜17時</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">お客様が今いただいているリフォームや新築の見積書をプロの視点で鑑定いたします。<br />
また、現在のお住まいの図面をお持ちいただければ、理想の間取りをご提案いたします。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->





























<!-- 画像 -->
<div class="column-image-left acms-col-sm-6">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/012/201312/52a0111b751f1.jpg"
 alt=""
 width="278"
 height="196">
<p class="caption">会場外観</p>
</div>






























<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">イベント限定特別価格コーナー</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->





























<!-- 画像 -->
<div class="column-image-center acms-col-sm-6">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/012/201312/52a0111b7af90.jpg"
 alt=""
 width="278"
 height="185">
<p class="caption">周辺地図</p>
</div>






























<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">システムバスやシステムキッチンなどの商品を特別価格でご提供いたします。台数に限りがありますのでお早めにご来場ください。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">イベント開催時の感染症予防対策について</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">イベントの詳しい内容について</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">感染症予防対策を行ったうえで開催いたします<br />
混雑を避けるため、事前のご予約をお願い致します</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">イベントの詳しい内容については当日の新聞折込チラシをご覧ください。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02"><i class="circle border-pink"></i>見逃せないプレゼントや特典がいっぱい！</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->











]]></description>
<category>久留米市内</category>
<guid isPermaLink="true">http://plaza-r.co.jp/event/kurume/lixil-kurume.html</guid>
<pubDate>Mon, 09 Mar 2026 17:15:20 +0900</pubDate>
</item>
<item>
<dc:creator>HP管理者</dc:creator>
<title>LIXIL大分ショールームにて開催</title>
<link>http://plaza-r.co.jp/event/oita/lixil-oita.html</link>
<description><![CDATA[















































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">相談会特典</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">5月23日（土）〜24日（日）にLIXIL大分ショールームにてリフォーム＋新築大相談会を開催します。<br />
リフォーム・新築をお考えの皆様、お見積やご相談は無料です。<br />
ホームページまたはお電話にてご予約のうえ、ご来場ください。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">ご相談やお見積り、ご成約いただいた方全員にプレゼントをご用意しております。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02">開催場所</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">LIXIL大分ショールーム</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">施工事例パネル大公開</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">〒870-0954 大分県大分市下郡中央2-4-16</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">実際にリフォームや新築をさせていただいた物件を写真にコメントを添えて一挙大公開いたします。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02">開催期間</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">相談コーナー開催</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">5月23日（土）〜24日（日）<br />
10時〜17時</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">お客様が今いただいているリフォームや新築の見積書をプロの視点で鑑定いたします。<br />
また、現在のお住まいの図面をお持ちいただければ、理想の間取りをご提案いたします。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->





























<!-- 画像 -->
<div class="column-image-left acms-col-sm-6">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/012/201308/5211775d9333f.jpg"
 alt=""
 width="450"
 height="338">
<p class="caption">会場外観</p>
</div>






























<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">イベント限定特別価格コーナー</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->





























<!-- 画像 -->
<div class="column-image-center acms-col-sm-6">
<a href="http://plaza-r.co.jp/archives/012/201308/large-52117765814c0.gif"data-rel="SmartPhoto" data-caption="周辺地図">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/012/201308/52117765814c0.gif"
 alt=""
 width="450"
 height="338">
</a>
<p class="caption">周辺地図</p>
</div>






























<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">システムバスやシステムキッチンなどの商品を特別価格でご提供いたします。台数に限りがありますのでお早めにご来場ください。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">イベントの詳しい内容について</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">イベント開催時の感染症予防対策について</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">イベントの詳しい内容については当日の新聞折込チラシをご覧ください。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">感染症予防対策を行ったうえで開催いたします<br />
混雑を避けるため、事前のご予約をお願い致します</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02"><i class="circle border-pink"></i>見逃せないプレゼントや特典がいっぱい！</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->











]]></description>
<category>大分市内</category>
<guid isPermaLink="true">http://plaza-r.co.jp/event/oita/lixil-oita.html</guid>
<pubDate>Mon, 09 Mar 2026 17:14:35 +0900</pubDate>
</item>
<item>
<dc:creator>HP管理者</dc:creator>
<title>TDY 福岡コラボレーション(キャナル)ショールームにて開催</title>
<link>http://plaza-r.co.jp/event/fukuoka/toto-fukuoka.html</link>
<description><![CDATA[















































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">相談会特典</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">4月4日(土) 〜5日（日）にTDY 福岡コラボレーション(キャナル)ショールームにてリフォーム＋新築大相談会を開催します。<br />
リフォーム・新築をお考えの皆様、お見積やご相談は無料です。<br />
是非お気軽にご来場ください。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">ご相談やお見積り、ご成約いただいた方全員にプレゼントをご用意しております。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02">開催場所</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">施工事例パネル大公開</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">TDY福岡コラボレーション(キャナル)ショールーム</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">実際にリフォームや新築をさせていただいた物件を写真にコメントを添えて一挙大公開いたします。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">〒812-0018　福岡県福岡市博多区住吉1-2-25　キャナルシティ・ビジネスセンタービル3F</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">相談コーナー開催</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02">開催期間</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">4月4日(土) 〜5日（日）<br />
10時〜17時</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">お客様が今いただいているリフォームや新築の見積書をプロの視点で鑑定いたします。<br />
また、現在のお住まいの図面をお持ちいただければ、理想の間取りをご提案いたします。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->





























<!-- 画像 -->
<div class="column-image-left acms-col-sm-6">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/012/201308/521179db13f56.jpg"
 alt=""
 width="450"
 height="338">
<p class="caption">会場外観</p>
</div>






























<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">イベント限定特別価格コーナー</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->





























<!-- 画像 -->
<div class="column-image-center acms-col-sm-6">
<a href="http://plaza-r.co.jp/archives/012/201412/large-548e5238dcb77.jpg"data-rel="SmartPhoto" data-caption="周辺地図">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/012/201412/548e5238dcb77.jpg"
 alt=""
 width="450"
 height="257">
</a>
<p class="caption">周辺地図</p>
</div>






























<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">システムバスやシステムキッチンなどの商品を特別価格でご提供いたします。台数に限りがありますのでお早めにご来場ください。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">イベントの詳しい内容について</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02">相談会開催風景</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->





























<!-- 画像 -->
<div class="column-image-left acms-col-sm-6">
<a href="http://plaza-r.co.jp/archives/012/201801/large-b9d23f1cc3cb24241029368d528c3a25.jpg"data-rel="SmartPhoto" data-caption="">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/012/201801/b9d23f1cc3cb24241029368d528c3a25.jpg"
 alt=""
 width="450"
 height="338">
</a>
</div>






























<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">イベントの詳しい内容については当日の新聞折込チラシをご覧ください。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->





























<!-- 画像 -->
<div class="column-image-center acms-col-sm-6">
<a href="http://plaza-r.co.jp/archives/012/201801/large-6382bf732cf3bf8276c97a0828537b9d.jpg"data-rel="SmartPhoto" data-caption="">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/012/201801/6382bf732cf3bf8276c97a0828537b9d.jpg"
 alt=""
 width="450"
 height="338">
</a>
</div>






























<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">イベント開催時の感染症予防対策について</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">感染症予防対策を行ったうえで開催いたします<br />
混雑を避けるため、事前のご予約をお願い致します</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03"><i class="circle border-pink"></i>見逃せないプレゼントや特典がいっぱい！</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02">TDY全商品部門（総合部門）全国第1位受賞！</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">全国約2,461社のTOTOリモデルクラブ会員企業が参加して商品の販売実績を競うTDYグリーンリモデルセール。<br />
その最高峰といえるTDY全商品部門（総合部門）で、当社は6年連続8度目（2009年度、2010年度、2012年度、2013年度、2014年度、2015年度、2016年度、2017年度）の全国第１位の栄冠を獲得いたしました。<br />
数多くのお客様のご支持をいただいたからこその受賞です。<br />
誠にありがとうございました。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->











]]></description>
<category>福岡市内</category>
<guid isPermaLink="true">http://plaza-r.co.jp/event/fukuoka/toto-fukuoka.html</guid>
<pubDate>Mon, 09 Mar 2026 17:10:02 +0900</pubDate>
</item>
<item>
<dc:creator>HP管理者</dc:creator>
<title>TOTO佐賀ショールームにて開催</title>
<link>http://plaza-r.co.jp/event/saga/toto-saga.html</link>
<description><![CDATA[















































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->




<h4 class="heading04">相談会特典</h4>

 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">4月4日(土) 〜5日（日）にTOTO佐賀ショールームにてリフォーム＋新築大相談会を開催します。<br />
リフォーム・新築をお考えの皆様、お見積やご相談は無料です。<br />
是非お気軽にご来場ください。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02">開催場所</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">ご相談やお見積り、ご成約いただいた方全員にプレゼントをご用意しております。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">TOTO佐賀ショールーム</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->




<h4 class="heading04">施工事例パネル大公開</h4>

 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">〒849-0932　佐賀県佐賀市鍋島町八戸溝952-5</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">実際にリフォームや新築をさせていただいた物件を写真にコメントを添えて一挙大公開いたします。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02">開催期間</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->




<h4 class="heading04">相談コーナー開催</h4>

 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">4月4日(土) 〜5日（日）<br />
10時〜17時</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">お客様が今いただいているリフォームや新築の見積書をプロの視点で鑑定いたします。<br />
また、現在のお住まいの図面をお持ちいただければ、理想の間取りをご提案いたします。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->





























<!-- 画像 -->
<div class="column-image-left acms-col-sm-6">
<a href="http://plaza-r.co.jp/archives/012/202306/large-98a72a54d68005cc73325c7d40811103.png"data-rel="SmartPhoto" data-caption="会場外観">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/012/202306/98a72a54d68005cc73325c7d40811103.png"
 alt=""
 width="450"
 height="254">
</a>
<p class="caption">会場外観</p>
</div>






























<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->




<h4 class="heading04">イベント限定特別価格コーナー</h4>

 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->





























<!-- 画像 -->
<div class="column-image-center acms-col-sm-6">
<a href="https://www.google.co.jp/maps/preview?hl=ja&amp;georestrict=input_srcid:9718532ebafeb198&amp;ie=UTF8&amp;view=map&amp;cid=7175489204160134718&amp;q=%EF%BC%B4%EF%BC%AF%EF%BC%B4%EF%BC%AF&amp;ved=0CB0QpQY&amp;ei=ow_vTK-HGKiwuQO-w-jaDg&amp;hq=%EF%BC%B4%EF%BC%AF%EF%BC%B4%EF%BC%AF&amp;hnear=&amp;ll=3" data-caption="">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/012/201403/532654ee4628d.jpg"
 alt=""
 width="450"
 height="321">
</a>
<p class="caption">周辺地図</p>
</div>






























<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">システムバスやシステムキッチンなどの商品を特別価格でご提供いたします。台数に限りがありますのでお早めにご来場ください。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02">相談会開催風景</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->




<h4 class="heading04">イベントの詳しい内容について</h4>

 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">イベントの詳しい内容については当日の新聞折込チラシをご覧ください。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->





























<!-- 画像 -->
<div class="column-image-left acms-col-sm-6">
<a href="http://plaza-r.co.jp/archives/012/201801/large-3171ac77edd094d3a935eea4deeb7b5a.jpg"data-rel="SmartPhoto" data-caption="">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/012/201801/3171ac77edd094d3a935eea4deeb7b5a.jpg"
 alt=""
 width="450"
 height="338">
</a>
</div>






























<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->





























<!-- 画像 -->
<div class="column-image-center acms-col-sm-6">
<a href="http://plaza-r.co.jp/archives/012/202001/large-0789558f957b5be9ed80c3bd1e7f8101.jpg"data-rel="SmartPhoto" data-caption="">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/012/202001/0789558f957b5be9ed80c3bd1e7f8101.jpg"
 alt=""
 width="450"
 height="338">
</a>
</div>






























<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">イベント開催時の感染症予防対策について</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">感染症予防対策を行ったうえで開催いたします<br />
混雑を避けるため、事前のご予約をお願い致します</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02"><i class="circle border-pink"></i>見逃せないプレゼントや特典がいっぱい！</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02">TDY全商品部門（総合部門）全国第1位受賞！</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">全国約2,461社のTOTOリモデルクラブ会員企業が参加して商品の販売実績を競うTDYグリーンリモデルセール。<br />
その最高峰といえるTDY全商品部門（総合部門）で、当社は6年連続8度目（2009年度、2010年度、2012年度、2013年度、2014年度、2015年度、2016年度、2017年度）の全国第１位の栄冠を獲得いたしました。<br />
数多くのお客様のご支持をいただいたからこその受賞です。<br />
誠にありがとうございました。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->











]]></description>
<category>佐賀市内</category>
<guid isPermaLink="true">http://plaza-r.co.jp/event/saga/toto-saga.html</guid>
<pubDate>Mon, 09 Mar 2026 17:09:21 +0900</pubDate>
</item>
<item>
<dc:creator>HP管理者</dc:creator>
<title>TOTO大分ショールームにて開催</title>
<link>http://plaza-r.co.jp/event/oita/toto-oita.html</link>
<description><![CDATA[















































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">4月4日(土) 〜5日（日）にTOTO大分ショールームにてリフォーム＋新築大相談会を開催します。<br />
リフォーム・新築をお考えの皆様、お見積やご相談は無料です。<br />
是非お気軽にご来場ください。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->




<h4 class="heading04">相談会特典</h4>

 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02">開催場所</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">ご相談やお見積り、ご成約いただいた方全員にプレゼントをご用意しております。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">TOTO大分ショールーム</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->




<h4 class="heading04">施工事例パネル大公開</h4>

 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">〒870-0147　大分県大分市小池原1158-1</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">実際にリフォームや新築をさせていただいた物件を写真にコメントを添えて一挙大公開いたします。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02">開催期間</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->




<h4 class="heading04">相談コーナー開催</h4>

 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">4月4日(土) 〜5日（日）<br />
10時〜17時</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">お客様が今いただいているリフォームや新築の見積書をプロの視点で鑑定いたします。<br />
また、現在のお住まいの図面をお持ちいただければ、理想の間取りをご提案いたします。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->




<h4 class="heading04">イベント限定特別価格コーナー</h4>

 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->





























<!-- 画像 -->
<div class="column-image-left acms-col-sm-6">
<a href="http://plaza-r.co.jp/archives/012/202306/large-d4fbaf57993437f4d86e12db7218147d.png"data-rel="SmartPhoto" data-caption="会場外観">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/012/202306/d4fbaf57993437f4d86e12db7218147d.png"
 alt=""
 width="450"
 height="320">
</a>
<p class="caption">会場外観</p>
</div>






























<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->





























<!-- 画像 -->
<div class="column-image-center acms-col-sm-6">
<a href="http://plaza-r.co.jp/archives/012/202306/large-6950b4e13038ad99d6bebaccb25d7629.gif"data-rel="SmartPhoto" data-caption="周辺地図">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/012/202306/6950b4e13038ad99d6bebaccb25d7629.gif"
 alt=""
 width="450"
 height="339">
</a>
<p class="caption">周辺地図</p>
</div>






























<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">システムバスやシステムキッチンなどの商品を特別価格でご提供いたします。台数に限りがありますのでお早めにご来場ください。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->




<h4 class="heading04">イベントの詳しい内容について</h4>

 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02">相談会開催風景</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">イベントの詳しい内容については当日の新聞折込チラシをご覧ください。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->





























<!-- 画像 -->
<div class="column-image-left acms-col-sm-6">
<a href="http://plaza-r.co.jp/archives/012/201801/large-7e69a574a8188f673ff6c573814fa9d7.jpg"data-rel="SmartPhoto" data-caption="">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/012/201801/7e69a574a8188f673ff6c573814fa9d7.jpg"
 alt=""
 width="450"
 height="338">
</a>
</div>






























<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->





























<!-- 画像 -->
<div class="column-image-center acms-col-sm-6">
<a href="http://plaza-r.co.jp/archives/012/201801/large-81541e37e7011a0f7d14c6ef514d46e2.jpg"data-rel="SmartPhoto" data-caption="">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/012/201801/81541e37e7011a0f7d14c6ef514d46e2.jpg"
 alt=""
 width="450"
 height="338">
</a>
</div>






























<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">イベント開催時の感染症予防対策について</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">混雑を避けるため、事前のご予約をお願い致します</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02"><i class="circle border-pink"></i>見逃せないプレゼントや特典がいっぱい！</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02">TDY全商品部門（総合部門）全国第1位受賞！</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">全国約2,461社のTOTOリモデルクラブ会員企業が参加して商品の販売実績を競うTDYグリーンリモデルセール。<br />
その最高峰といえるTDY全商品部門（総合部門）で、当社は6年連続8度目（2009年度、2010年度、2012年度、2013年度、2014年度、2015年度、2016年度、2017年度）の全国第１位の栄冠を獲得いたしました。<br />
数多くのお客様のご支持をいただいたからこその受賞です。<br />
誠にありがとうございました。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->











]]></description>
<category>大分市内</category>
<guid isPermaLink="true">http://plaza-r.co.jp/event/oita/toto-oita.html</guid>
<pubDate>Mon, 09 Mar 2026 17:08:23 +0900</pubDate>
</item>
<item>
<dc:creator>HP管理者</dc:creator>
<title>TOTO久留米ショールームにて開催</title>
<link>http://plaza-r.co.jp/event/kurume/toto-kurume.html</link>
<description><![CDATA[















































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">4月4日(土) 〜5日（日）にTOTO久留米ショールームにてリフォーム＋新築大相談会を開催します。<br />
リフォーム・新築をお考えの皆様、お見積やご相談は無料です。<br />
是非お気軽にご来場ください。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">相談会特典</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">ご相談やお見積り、ご成約いただいた方全員にプレゼントをご用意しております。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02">開催場所</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">TOTO久留米ショールーム</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">施工事例パネル大公開</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">〒830-0001　福岡県久留米市小森野4-9-1</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">実際にリフォームや新築をさせていただいた物件を写真にコメントを添えて一挙大公開いたします。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03"><span class="color-lite-orange"></span>相談コーナー開催</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02">開催期間</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">4月4日(土) 〜5日（日）<br />
10時〜17時</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">お客様が今いただいているリフォームや新築の見積書をプロの視点で鑑定いたします。<br />
また、現在のお住まいの図面をお持ちいただければ、理想の間取りをご提案いたします。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">イベント限定特別価格コーナー</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->





























<!-- 画像 -->
<div class="column-image-left acms-col-sm-6">
<a href="http://plaza-r.co.jp/archives/012/201801/large-568b56237ad12214b134bc4f3201c82f.jpg"data-rel="SmartPhoto" data-caption="会場外観">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/012/201801/568b56237ad12214b134bc4f3201c82f.jpg"
 alt=""
 width="450"
 height="338">
</a>
<p class="caption">会場外観</p>
</div>






























<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->





























<!-- 画像 -->
<div class="column-image-center acms-col-sm-6">
<a href="http://plaza-r.co.jp/archives/012/201308/large-521176116984c.gif"data-rel="SmartPhoto" data-caption="周辺地図">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/012/201308/521176116984c.gif"
 alt=""
 width="450"
 height="338">
</a>
<p class="caption">周辺地図</p>
</div>






























<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">システムバスやシステムキッチンなどの商品を特別価格でご提供いたします。台数に限りがありますのでお早めにご来場ください。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02">相談会開催風景</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">イベントの詳しい内容について</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->





























<!-- 画像 -->
<div class="column-image-left acms-col-sm-6">
<a href="http://plaza-r.co.jp/archives/012/201801/large-9b8b0963c6eb936c00b3351747e6d2fa.jpg"data-rel="SmartPhoto" data-caption="">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/012/201801/9b8b0963c6eb936c00b3351747e6d2fa.jpg"
 alt=""
 width="450"
 height="338">
</a>
</div>






























<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">イベントの詳しい内容については当日の新聞折込チラシをご覧ください。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->





























<!-- 画像 -->
<div class="column-image-center acms-col-sm-6">
<a href="http://plaza-r.co.jp/archives/012/201801/large-fb59379ecc733c0a25471acc75010b1a.jpg"data-rel="SmartPhoto" data-caption="">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/012/201801/fb59379ecc733c0a25471acc75010b1a.jpg"
 alt=""
 width="450"
 height="338">
</a>
</div>






























<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">イベント開催時の感染症予防対策について</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">感染症予防対策を行ったうえで開催いたします<br />
混雑を避けるため、事前のご予約をお願い致します</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02"><i class="circle border-pink"></i>見逃せないプレゼントや特典がいっぱい！</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02">TDY全商品部門（総合部門）全国第1位受賞！</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">全国約2,461社のTOTOリモデルクラブ会員企業が参加して商品の販売実績を競うTDYグリーンリモデルセール。<br />
その最高峰といえるTDY全商品部門（総合部門）で、当社は6年連続8度目（2009年度、2010年度、2012年度、2013年度、2014年度、2015年度、2016年度、2017年度）の全国第１位の栄冠を獲得いたしました。<br />
数多くのお客様のご支持をいただいたからこその受賞です。<br />
誠にありがとうございました。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->











]]></description>
<category>久留米市内</category>
<guid isPermaLink="true">http://plaza-r.co.jp/event/kurume/toto-kurume.html</guid>
<pubDate>Mon, 09 Mar 2026 17:07:44 +0900</pubDate>
</item>
<item>
<dc:creator>HP管理者</dc:creator>
<title>TOTO福岡南ショールームにて開催</title>
<link>http://plaza-r.co.jp/event/dazaifu/toto-fukuokaminami.html</link>
<description><![CDATA[















































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">4月4日(土) 〜5日（日）にTOTO福岡南ショールームにてリフォーム＋新築大相談会を開催します。<br />
リフォーム・新築をお考えの皆様、お見積やご相談は無料です。<br />
是非お気軽にご来場ください。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">相談会特典</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02">開催場所</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">ご相談やお見積り、ご成約いただいた方全員にプレゼントをご用意しております。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">TOTO福岡南ショールーム</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">施工事例パネル大公開</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">実際にリフォームや新築をさせていただいた物件を写真にコメントを添えて一挙大公開いたします。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">〒818-0134 福岡県太宰府市大佐野3-11-1</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02">開催期間</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">相談コーナー開催</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">4月4日(土) 〜5日（日）<br />
10時〜17時</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">お客様が今いただいているリフォームや新築の見積書をプロの視点で鑑定いたします。<br />
また、現在のお住まいの図面をお持ちいただければ、理想の間取りをご提案いたします。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->





























<!-- 画像 -->
<div class="column-image-left">
<a href="http://plaza-r.co.jp/archives/012/201801/large-87266da328a20567f83b3291826eae3e.jpg"data-rel="SmartPhoto" data-caption="会場外観">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/012/201801/87266da328a20567f83b3291826eae3e.jpg"
 alt=""
 width="450"
 height="338">
</a>
<p class="caption">会場外観</p>
</div>






























<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">イベント限定特別価格コーナー</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">システムバスやシステムキッチンなどの商品を特別価格でご提供いたします。台数に限りがありますのでお早めにご来場ください。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->





























<!-- 画像 -->
<div class="column-image-center">
<a href="http://plaza-r.co.jp/archives/012/201308/large-52117a4221d7b.gif"data-rel="SmartPhoto" data-caption="周辺地図">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/012/201308/52117a4221d7b.gif"
 alt=""
 width="450"
 height="338">
</a>
<p class="caption">周辺地図</p>
</div>






























<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">イベントの詳しい内容について</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02">相談会開催風景</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">イベントの詳しい内容については当日の新聞折込チラシをご覧ください。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->





























<!-- 画像 -->
<div class="column-image-left">
<a href="http://plaza-r.co.jp/archives/012/201801/large-fda0c2a586521d61704f51223e6ae110.jpg"data-rel="SmartPhoto" data-caption="">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/012/201801/fda0c2a586521d61704f51223e6ae110.jpg"
 alt=""
 width="450"
 height="338">
</a>
</div>






























<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->





























<!-- 画像 -->
<div class="column-image-center">
<a href="http://plaza-r.co.jp/archives/012/201801/large-fc0f0d4f622d94c2f29244fa60f6abff.jpg"data-rel="SmartPhoto" data-caption="">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/012/201801/fc0f0d4f622d94c2f29244fa60f6abff.jpg"
 alt=""
 width="450"
 height="338">
</a>
</div>






























<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">イベント開催時の感染症予防対策について</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">感染症予防対策を行ったうえで開催いたします<br />
混雑を避けるため、事前のご予約をお願い致します</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02"><i class="circle border-pink"></i>見逃せないプレゼントや特典がいっぱい！</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02">TDY全商品部門（総合部門）全国第1位受賞！</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">全国約2,461社のTOTOリモデルクラブ会員企業が参加して商品の販売実績を競うTDYグリーンリモデルセール。<br />
その最高峰といえるTDY全商品部門（総合部門）で、当社は6年連続8度目（2009年度、2010年度、2012年度、2013年度、2014年度、2015年度、2016年度、2017年度）の全国第１位の栄冠を獲得いたしました。<br />
数多くのお客様のご支持をいただいたからこその受賞です。<br />
誠にありがとうございました。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->











]]></description>
<category>太宰府市内</category>
<guid isPermaLink="true">http://plaza-r.co.jp/event/dazaifu/toto-fukuokaminami.html</guid>
<pubDate>Mon, 09 Mar 2026 17:06:51 +0900</pubDate>
</item>
<item>
<dc:creator>HP管理者</dc:creator>
<title>TOTOミュージアムにて開催</title>
<link>http://plaza-r.co.jp/event/kitakyushu/toto-kitakyushu.html</link>
<description><![CDATA[















































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">相談会特典</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">4月4日(土) 〜5日（日）TOTOミュージアムにてリフォーム＋新築大相談会を開催します。<br />
リフォーム・新築をお考えの皆様、お見積やご相談は無料です。<br />
是非お気軽にご来場ください。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02">開催場所</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">ご相談やお見積り、ご成約いただいた方全員にプレゼントをご用意しております。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">TOTOミュージアム</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">施工事例パネル大公開</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">実際にリフォームや新築をさせていただいた物件を写真にコメントを添えて一挙大公開いたします。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">〒802-8601 北九州市小倉北区中島2-1-1　1F TOTO北九州ショールーム</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">相談コーナー開催</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02">開催期間</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">お客様が今いただいているリフォームや新築の見積書をプロの視点で鑑定いたします。<br />
また、現在のお住まいの図面をお持ちいただければ、理想の間取りをご提案いたします。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">4月4日(土) 〜5日（日）<br />
10時〜17時</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->





























<!-- 画像 -->
<div class="column-image-left acms-col-sm-6">
<a href="http://plaza-r.co.jp/archives/012/201508/large-55e417a47679a.jpg"data-rel="SmartPhoto" data-caption="会場外観">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/012/201508/55e417a47679a.jpg"
 alt=""
 width="450"
 height="318">
</a>
<p class="caption">会場外観</p>
</div>






























<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">イベント限定特別価格コーナー</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->





























<!-- 画像 -->
<div class="column-image-center acms-col-sm-6">
<a href="http://plaza-r.co.jp/archives/012/201508/large-55e4176a337c9.gif"data-rel="SmartPhoto" data-caption="周辺地図">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/012/201508/55e4176a337c9.gif"
 alt=""
 width="450"
 height="339">
</a>
<p class="caption">周辺地図</p>
</div>






























<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">システムバスやシステムキッチンなどの商品を特別価格でご提供いたします。台数に限りがありますのでお早めにご来場ください。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02">相談会開催風景</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">イベントの詳しい内容について</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->





























<!-- 画像 -->
<div class="column-image-left acms-col-sm-6">
<a href="http://plaza-r.co.jp/archives/012/201801/large-58eebe59aa239bdea274a21e35981b90.jpg"data-rel="SmartPhoto" data-caption="">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/012/201801/58eebe59aa239bdea274a21e35981b90.jpg"
 alt=""
 width="450"
 height="338">
</a>
</div>






























<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">イベントの詳しい内容については当日の新聞折込チラシをご覧ください。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->





























<!-- 画像 -->
<div class="column-image-center acms-col-sm-6">
<a href="http://plaza-r.co.jp/archives/012/201801/large-12ca67a3fcfb991a1db2d00b1b3932dd.jpg"data-rel="SmartPhoto" data-caption="">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/012/201801/12ca67a3fcfb991a1db2d00b1b3932dd.jpg"
 alt=""
 width="450"
 height="338">
</a>
</div>






























<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">イベント開催時の感染症予防対策について</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">感染症予防対策を行ったうえで開催いたします<br />
混雑を避けるため、事前のご予約をお願い致します</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02"><i class="circle border-pink"></i>見逃せないプレゼントや特典がいっぱい！</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02">TDY全商品部門（総合部門）全国第1位受賞！</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">全国約2,461社のTOTOリモデルクラブ会員企業が参加して商品の販売実績を競うTDYグリーンリモデルセール。<br />
その最高峰といえるTDY全商品部門（総合部門）で、当社は6年連続8度目（2009年度、2010年度、2012年度、2013年度、2014年度、2015年度、2016年度、2017年度）の全国第１位の栄冠を獲得いたしました。<br />
数多くのお客様のご支持をいただいたからこその受賞です。<br />
誠にありがとうございました。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->











]]></description>
<category>北九州市内</category>
<guid isPermaLink="true">http://plaza-r.co.jp/event/kitakyushu/toto-kitakyushu.html</guid>
<pubDate>Mon, 09 Mar 2026 17:06:19 +0900</pubDate>
</item>
<item>
<dc:creator>HP管理者</dc:creator>
<title>TOTO福岡東ショールームにて開催</title>
<link>http://plaza-r.co.jp/event/koga/toto-fukuokahigashi.html</link>
<description><![CDATA[















































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">相談会特典</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">4月4日(土) 〜5日（日）にTOTO福岡東ショールームにてリフォーム＋新築大相談会を開催します。<br />
リフォーム・新築をお考えの皆様、お見積やご相談は無料です。<br />
是非お気軽にご来場ください。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">ご相談やお見積り、ご成約いただいた方全員にプレゼントをご用意しております。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02">開催場所</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">TOTO福岡東ショールーム</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">施工事例パネル大公開</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">〒811-3112　福岡県古賀市花見東1-15-18</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">実際にリフォームや新築をさせていただいた物件を写真にコメントを添えて一挙大公開いたします。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02">開催期間</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">相談コーナー開催</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">4月4日(土) 〜5日（日）<br />
10時〜17時</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">お客様が今いただいているリフォームや新築の見積書をプロの視点で鑑定いたします。<br />
また、現在のお住まいの図面をお持ちいただければ、理想の間取りをご提案いたします。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->





























<!-- 画像 -->
<div class="column-image-left acms-col-sm-6">
<a href="http://plaza-r.co.jp/archives/012/201801/large-e2fed474e123e69833a61b132db03dbe.jpg"data-rel="SmartPhoto" data-caption="会場外観">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/012/201801/e2fed474e123e69833a61b132db03dbe.jpg"
 alt=""
 width="450"
 height="338">
</a>
<p class="caption">会場外観</p>
</div>






























<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">イベント限定特別価格コーナー</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->





























<!-- 画像 -->
<div class="column-image-center acms-col-sm-6">
<a href="http://plaza-r.co.jp/archives/012/201308/large-52117b473342e.gif"data-rel="SmartPhoto" data-caption="周辺地図">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/012/201308/52117b473342e.gif"
 alt=""
 width="450"
 height="338">
</a>
<p class="caption">周辺地図</p>
</div>






























<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">システムバスやシステムキッチンなどの商品を特別価格でご提供いたします。台数に限りがありますのでお早めにご来場ください。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02">相談会開催風景</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">イベントの詳しい内容について</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->





























<!-- 画像 -->
<div class="column-image-left acms-col-sm-6">
<a href="http://plaza-r.co.jp/archives/012/202001/large-cd2a950a5788c9c469f91f598029eea3.jpg"data-rel="SmartPhoto" data-caption="">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/012/202001/cd2a950a5788c9c469f91f598029eea3.jpg"
 alt=""
 width="450"
 height="338">
</a>
</div>






























<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">イベントの詳しい内容については当日の新聞折込チラシをご覧ください。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->





























<!-- 画像 -->
<div class="column-image-center acms-col-sm-6">
<a href="http://plaza-r.co.jp/archives/012/201801/large-8d401cc8b03169894acb34df49822f35.jpg"data-rel="SmartPhoto" data-caption="">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/012/201801/8d401cc8b03169894acb34df49822f35.jpg"
 alt=""
 width="450"
 height="338">
</a>
</div>






























<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">イベント開催時の感染症予防対策について</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">感染症予防対策を行ったうえで開催いたします<br />
混雑を避けるため、事前のご予約をお願い致します</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02"><i class="circle border-pink"></i>見逃せないプレゼントや特典がいっぱい！</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02">TDY全商品部門（総合部門）全国第1位受賞！</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">全国約2,461社のTOTOリモデルクラブ会員企業が参加して商品の販売実績を競うTDYグリーンリモデルセール。<br />
その最高峰といえるTDY全商品部門（総合部門）で、当社は6年連続8度目（2009年度、2010年度、2012年度、2013年度、2014年度、2015年度、2016年度、2017年度）の全国第１位の栄冠を獲得いたしました。<br />
数多くのお客様のご支持をいただいたからこその受賞です。<br />
誠にありがとうございました。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->











]]></description>
<category>古賀市内</category>
<guid isPermaLink="true">http://plaza-r.co.jp/event/koga/toto-fukuokahigashi.html</guid>
<pubDate>Mon, 09 Mar 2026 17:06:00 +0900</pubDate>
</item>
<item>
<dc:creator>HP管理者</dc:creator>
<title>LIXILショールーム福岡にて開催</title>
<link>http://plaza-r.co.jp/event/fukuoka/lixil-fukuoka.html</link>
<description><![CDATA[















































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">1月24日（土）〜25日（日）にLIXILショールーム福岡にてリフォーム＋新築大相談会を開催します。<br />
リフォーム・新築をお考えの皆様、お見積やご相談は無料です。<br />
ホームページまたはお電話にてご予約のうえ、ご来場ください。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">相談会特典</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02">開催場所</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">ご相談やお見積り、ご成約いただいた方全員にプレゼントをご用意しております。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">LIXILショールーム福岡</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">施工事例パネル大公開</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">〒812-0897 福岡県福岡市博多区半道橋2-15-10</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">実際にリフォームや新築をさせていただいた物件を写真にコメントを添えて一挙大公開いたします。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02">開催期間</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">相談コーナー開催</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">お客様が今いただいているリフォームや新築の見積書をプロの視点で鑑定いたします。<br />
また、現在のお住まいの図面をお持ちいただければ、理想の間取りをご提案いたします。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">1月24日（土）〜25日（日）<br />
10時〜17時</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->





























<!-- 画像 -->
<div class="column-image-left">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/012/201308/52117964e64e2.jpg"
 alt=""
 width="450"
 height="338">
<p class="caption">会場外観</p>
</div>






























<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">イベント限定特別価格コーナー</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->





























<!-- 画像 -->
<div class="column-image-center">
<a href="http://plaza-r.co.jp/archives/012/201412/large-548e52edaf7d7.jpg"data-rel="SmartPhoto" data-caption="周辺地図">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/012/201412/548e52edaf7d7.jpg"
 alt=""
 width="450"
 height="315">
</a>
<p class="caption">周辺地図</p>
</div>






























<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">システムバスやシステムキッチンなどの商品を特別価格でご提供いたします。台数に限りがありますのでお早めにご来場ください。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">イベントの詳しい内容について</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02">相談会開催風景</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">イベントの詳しい内容については当日の新聞折込チラシをご覧ください。</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->





























<!-- 画像 -->
<div class="column-image-left">
<a href="http://plaza-r.co.jp/archives/012/202001/large-371411ec3229c6dfa6c1d161f638d98e.jpg"data-rel="SmartPhoto" data-caption="">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/012/202001/371411ec3229c6dfa6c1d161f638d98e.jpg"
 alt=""
 width="450"
 height="338">
</a>
</div>






























<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->





























<!-- 画像 -->
<div class="column-image-center">
<a href="http://plaza-r.co.jp/archives/012/201801/large-39e07c39410df20de52b81624a904f80.jpg"data-rel="SmartPhoto" data-caption="">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/012/201801/39e07c39410df20de52b81624a904f80.jpg"
 alt=""
 width="450"
 height="338">
</a>
</div>






























<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->



<h3 class="heading03">イベント開催時の感染症予防対策について</h3>


 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->

<p class="text01">感染症予防対策を行ったうえで開催いたします<br />
混雑を避けるため、事前のご予約をお願い致します</p>




 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->

















<!-- テキスト -->


<h2 class="heading02"><i class="circle border-pink"></i>見逃せないプレゼントや特典がいっぱい！</h2>



 
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->
























































<!--
  カスタムユニットの**出力**。編集画面は `admin/entry/unit/extend.html`。

  ⚠ ブロック名は `unit#`。編集画面側は `#` 無しの
     タイプ名そのままなので、片方だけ直すと**エラーを出さずに何も出なくなる**。

  ⚠ フィールド名は `` 抜きで書く（保存時に `Field::retouchCustomUnit()` が
     末尾の id を落とすため）。編集画面の `unit_space_class` は
     ここでは ``。

  ⚠ **a-blog cms はカスタムユニットに器を付けない。** 素の HTML がそのまま
     本文に並ぶので、`.column-image` のようなクラスは自分で書く。

  ⚠ **編集設定への登録が別に要る。** テンプレートを置いただけでは
     ユニット追加メニューに出てこない。管理ページ > コンフィグ > 編集設定 で
     「ユニット追加ボタン」にタイプ名を足すこと（`column_add_type` ＋
     `column_def_add__type`）。**編集セットごと**に必要で、
     このプロジェクトは `reform2026`（設定セット 6）と
     `reform2026_case`（同 10・施工事例 bid 2 用）の2つがある。
-->

<!--
  余白ユニット。

    プリセット   <div class="spacer spacer_l" aria-hidden="true"></div>
    クラス指定   <div class="spacer mtSp_s mtPc_xl" aria-hidden="true"></div>

  ⚠ **クラス指定（項目2）に値があればそちらだけを出し、プリセット（項目1）の
     `spacer_*` は付けない。** 両方付けると `.spacer_l` の height と `mt_*` の
     margin が足し算になり、編集者から見て「クラスを書いたのに値が合わない」
     という壊れ方をする。

  ⚠ どちらも空のときは `.spacer` だけが出て高さ 0（間隔ゼロ）になる。
     編集画面は未選択のときに M が checked になるので、通常はここに落ちない。

  ⚠ `` は a-blog cms が HTML エスケープして出すので、
     `"` を入れられても属性からは抜け出せない。`[raw]` を付けないこと。

  ⚠ 中身が無いので読み上げには元から出ないが、`aria-hidden` を明示しておく。
  スタイルは `src/style/front/component/spacer/_spacer.scss` と
  `src/style/front/utility/_spacing.scss`。
-->


<!--
  ボタンユニット。

    <a href="/guide/" class="btn01 btn_sky">リフォームの流れを見る</a>

  ⚠ **クラスは `.btn01` ＋ 色クラスの2枚だけ。** 形・寸法・右端の矢印・中央寄せは
     `.btn01` が持ち（`component/button/_button.scss` が `.btn` / `.btn_unit` /
     `.btn_arrow` の各セレクタに `.btn01` を足してある）、色は併記のクラスが決める。
     **`.btn btn_unit btn_arrow` を並べないこと** —— 並べる前提で組んでいない。

  ⚠ **文言が空のときはボタンごと出さない。** 空の `<a>` を出すと 245x70 の
     色付きの箱だけが公開ページに残る（実測で確認済み）。
     ⚠⚠ **`unit_btn_text:veil` のブロック（BEGIN/END で囲む形）は使えない**（2026-08-22 実測）。
     カスタムユニットの描画は `Custom::render` が親ブロックに変数を add する
     だけで veil ブロックを個別に登録しないため、**値が空でも中身が出てしまう**。
     エラーは出ないので気付けない。**`BEGIN_IF` を使うこと。**
     ✅ **`BEGIN_IF` の入れ子は動く**（同日実測。href の有無との2段で確認）。

  ⚠ **色が空でも壊れない。** `.btn01` は色クラスが付かなかったときの保険として
     ブルーを持っている（`_button.scss` の「色クラスが付かなかったときの保険」）。

  ⚠ **`` は a-blog cms が HTML エスケープして出す**ので、`"` を
     入れられても属性から抜け出せない。`[raw]` を付けないこと。
     🔴 ただし `javascript:` スキームは CSS でもエスケープでも防げない。
     編集できるのは管理者だけなので受け入れているが、**権限を広げるときは
     バリデータ（`unit_btn_url:v#regex`）で `^(/|https?://)` に絞ること**。

  ⚠ 外部リンクの `open_in_new` は付かない。あれは `.textLink[href^='http']` の
     指定で、本文中のテキストリンク専用（`component/entry-body`）。カンプの
     ボタンにもアイコンは無く、右端の矢印は `.btn01` の ::after が出す。

  ✅ **「別タブで開く」の項目は要らない。** 外部ドメインのリンクには
     a-blog cms 同梱の `externalLinks`（`src/js/lib/build-in.js`。`main.js` が
     読んでいる）が **`target="_blank"` と `rel="noopener noreferrer"` を
     実行時に付ける**。自ホストのリンクには付かない。カンプの CMS登録 欄も
     「リンク先・文言・色の3つ」なので、項目は増やさない。
-->


<!--
  区切り線ユニット。編集画面は `admin/entry/unit/extend.html`。

    <hr class="hr01" />

  ⚠ **クラスはここに直書きする。編集画面の `unit_hr_marker` とは繋げないこと。**
     あちらは値を使わない保険の隠しフィールドで、`` を出力に使うと
     「値が消えたときにクラスも消える」という壊れ方の口ができる。
     ✅ **フィールドが1つも無くても公開側は空にならない**（2026-08-27 実測。
     `Common\Helper::loadField()` が `new Field()` を先に作るので 0 件でも空の Field が
     返る）。残している理由と実測の中身は編集画面側のコメントが正。

  ⚠ **`hr01` はカンプ支給のクラス名ではない。** カンプ（「ベース-ユニットパーツ」）は
     区切り線を**クラス無しの `<hr>`** で描いており、支給された16個のクラス一覧にも
     入っていない。`.heading02` / `.ul01` / `.table01` / `.btn01` と同じ連番の規則に
     合わせて 2026-08-27 に決めた名前。**CMS 側に登録する外部の名前と同じ扱い**なので、
     developkits の命名規則（ブロック_要素）に寄せて直さないこと。

  ⚠ **スタイルは要素セレクタ側（`hr`）が持っている**
     （`component/entry-body/_entry-body.scss` の「区切り線」の節。1px の #999 で
     4px 実線 / 4px 空きの破線）。`<hr class="hr01">` は `hr` にも当たるので
     見た目・余白・`clear: both` はそのまま効く。**SCSS 側に `.hr01` を足していない**
     のは、`:where(hr, .column-table)`（0,1,0）と `h2 + :not(…)`（0,1,1）の詳細度の
     釣り合いで「見出しの直後だけ 24px」を出しているため（同ファイルの注記）。
     クラスを足すと詳細度が動いてこの出し分けが壊れる。

  ⚠ **`.entry_body` 側が持つのは `margin-top` だけ**（SP 56 / PC 88px）。下の空きは
     次のユニットの `margin-top` が決める（段落なら SP 28 / PC 44px）。ユニット側では
     どちらも持たない。
-->


<!--
  旧ビフォーアフターユニット。編集画面は `admin/entry/unit/extend.html`。

    <div class="beforeAfter">
      <figure class="beforeAfter_item"> 写真 + 「施工前」 + 説明文 </figure>
      <span class="beforeAfter_arrow"><svg class="beforeAfter_arrowIcon">…</svg></span>
      <figure class="beforeAfter_item"> 写真 + 「施工後」 + 説明文 </figure>
    </div>

  ⚠ **マークアップは `static_html/case-detail.html` の `.beforeAfter` と同一。**
     スタイルは `src/style/front/component/before-after/_before-after.scss`。
     **片方を直したらもう片方も直すこと**（矢印の幅 20px は
     996 = 464 + 24 + 20 + 24 + 464 で写真の幅を決めているので、
     別のものに替えると写真が痩せる）。
  ⚠⚠ **矢印はアイコンフォントではなくインライン SVG**（花田さんが 2026-08-26 に
     カンプから起こしたもの）。カンプの `Vector 52` は**ブランド青・太さ 4px の
     折れ線**で、`arrow_forward_ios` では出せない —— Material のシェブロンは
     高さ÷幅が wght300 で 1.7437 なのに対し、カンプは PC 2.2 / SP 2.27 と
     明らかに細長く、太さも別物。

  ⚠ **写真が2枚そろっていないときは何も出さない。** 2枚を横に並べて
     見比べる形なので、片方だけだと矢印と半分の箱だけが残る。
     編集画面の説明文にも「2枚とも必要」と書いてある。
     ✅ `BEGIN_IF` の入れ子は動く（2026-08-22 実測）。

  ⚠ **見出しは `unit_ba_head` がチェックされたユニットだけが出す。**
     カンプの固定セクション（`<section class="caseDetail_ba">` + 見出し）は
     ユニットからは作れない（自分より後ろの兄弟ユニットを包めない）ので、
     **見出しだけを `.beforeAfter` の直前に置いて、余白を CSS で作っている**。
     ⚠ **クラスを2枚付けているのは意図的。**
       `.caseDetail_baHead`  … 見た目（16/20px 太字 ＋ 右へ伸びるブランド青 4px の罫線）。
                               定義は `pages/_case-detail.scss`。受賞版の「平面図」の
                               節も同じクラスを使っているので**複製せず借りている**
       `.beforeAfter_head`   … `.entry_body` の中での上下の余白だけを持つ。
                               定義は `component/before-after/_before-after.scss`
     🚩 `.caseDetail_baHead` はページ固有の名前なので、本来はコンポーネントへ
        引き上げたい。**このユニットは編集セット10（施工事例 bid 2）にしか
        登録していない**ので実害は無いが、他ブログで使うことになったら移すこと。

  ⚠ **`alt` は `@alt` の値をそのまま出す**（2026-08-26 に `alt=""` 固定から変更）。
     移行元の画像ユニットに 3,091件 の代替テキストが入っており、
     **捨てずに引き継ぐ**ため。空なら `alt=""` になり、直後の `<figcaption>`
     （「施工前」＋説明文）が `<figure>` の読み上げ名になるので情報は落ちない。

  ⚠ **`width` / `height` は `@x` / `@y` があるときだけ出す。**
     `.beforeAfter_img` は `aspect-ratio: 3/2` で、既定は `object-fit: cover`。
     **縦位置の写真のときだけ `beforeAfter_imgPortrait` を足してレターボックス**
     （`object-fit: contain` ＋ 地色 #f3f3f3）にする。判定は `@y > @x`。
     ⚠ **この修飾は花田さんがカンプ（`275:*`）から起こしたもの。** 器
     （`image 45`）は 464x309・#F3F3F3 で、中の写真は実寸比のまま中央に置かれる。
     `width` / `height` は表示比を決めないが、読み込み中のガタつき（CLS）を抑える。
     ⚠ 移行元の画像（`@path` に入る素のファイル）は 200〜308px しかなく、
     `archives/` に 400〜1200px の `large-` が別にある。**移行 SQL では
     `large-` のほうを `@path` に入れる**（カンプの表示幅が PC 464px のため）。

  ⚠ **拡大表示は smartphoto**（2026-08-26 追加。設計①の指示）。テーマの
     `src/js/main.js` が `smartPhoto(context)` を呼んでおり、拾うセレクタは
     `a[data-rel^=SmartPhoto], .js-smartphoto`（`src/js/lib/build-in.js:100`）。
     `data-group` を施工前・施工後で揃えてあるので、拡大したまま2枚を行き来できる。
     ⚠ **リンク先は `@largePath` があればそちら、無ければ `@path`。**
       移行データは `@largePath` を持たない（`@path` に旧サイトの `large-` を
       そのまま入れる）ので `@path` に落ちる。**それでも意味はある** ——
       器は 464px なのに元は最大 1200px あるので、拡大すると実際に大きく見える。
     ✅ **画像ユニット（補足写真）も同じ smartphoto に乗っている**（2026-08-26 実測）。
       `unit.html` が `<a href=""  data-group="">` を出し、
       `` の実体は `entry_body_image_viewer`。**既定値が
       `data-rel="SmartPhoto"`**（`private/config.system.default.yaml:483`）なので
       そのまま繋がる。施工事例・イベントの実ページで `prettyPhoto` 0件 /
       `data-rel="SmartPhoto"` を確認済み。
       ⚠ `acms_config` には旧サイト由来の `rel="prettyPhoto[]"` が
       bid 1 / 2 に残っているが**使われていない**（V2 モジュールはこの行を読まない）。
       紛らわしいので消してよいが、消さなくても動作は変わらない。

  ⚠ **説明文は `[nl2br]` を通す。** textarea なので改行が入りうる。
     `` は既定で HTML エスケープされるため `[raw]` は付けない。

  ⚠ **`.entry_body` 内での上余白の出どころ。**
       見出し無し … `pages/_case-detail.scss` の `.beforeAfter `
                    （あのルールはページ名でネストされていないので全体に掛かる）
       見出しあり … `.entry_body .beforeAfter_head` が 48/72px、続く
                    `.beforeAfter` は 24/48px に抑える
                    （`component/before-after/_before-after.scss`）
     ⚠ `_entry-body.scss` のユニット間余白リスト（`:where(…)` 28/44px）には
       `.beforeAfter` を**入れていない**。上の2つで足りているため。
-->
<!--
  ══════════════════════════════════════════════════════════════
  ビフォーアフター（新／メディア管理版）　`unit#custom_unit_ba`
  ══════════════════════════════════════════════════════════════

  **マークアップは旧版（`unit#custom_unit_ba_old`）と1文字も変えていない。**
  スタイルは `component/before-after/_before-after.scss` を共有する。
  **片方を直したらもう片方も直すこと。**

  ■ 旧版との差は写真の取り出し方だけ（`Media\Helper::injectMediaField` の実測）

  | | 旧（旧画像CF） | 新（新画像CF＝メディア管理） |
  |---|---|---|
  | 画像URL | `/archives/` ＋ `` | **`/media/` ＋ ``** |
  | 拡大用 | ``（無ければ `@path`） | **`@largePath` は無い。`@path` を使う** |
  | 寸法 | `` / `` | **`` / ``** |
  | 代替テキスト | ユニット側の `@alt` | **メディア管理側の `@alt`**（`media_field_3`） |

  🔴🔴 **`@path` は「メディアディレクトリからの相対パス」であってフルURLではない**
     （2026-08-27 実測。最初フルURLだと思って前置を省き、画像が全部 404 になった）。
     `Media\Helper::injectMediaField` は `Common::resolveUrl($path, MEDIA_LIBRARY_DIR)`
     を通すが、**`resolveUrl` が offset（＝ `media/`）を足すのは API ビルドか
     V2 モジュールのときだけ**（`php/Services/Common/Helper.php` の
     `if (isApiBuildOrV2Module())`）。カスタムユニットは `Common::setForceV1Build(true)`
     の従来記法なので**この分岐に入らず、`026/202608/xxx.png?v=…` がそのまま返る**。
     **`/media/`（= `/media/`）を自分で前置すること。**
     ⚠ Twig 側（`entry.fields.*.value.path`）は V2 モジュール経由なので `/media/` 込みで
     返る。**同じ `@path` でも経路によって中身が違う**ので、片方の挙動から推測しないこと。

  🔑 **キャッシュバスティングのクエリ（`?v=…`）は `@path` に既に含まれている。**

  🔑 **メディアは1ファイルなので拡大用の別サイズが無い。** 旧版は `large-` を持って
     いたが、こちらは同じ画像を拡大に使う。SmartPhoto の見え方は変わらない
     （元画像が表示サイズより大きいため）。

  ⚠ **`injectMediaField` は `Custom::render` が `$force = true` で呼んでいる**
     （`php/Services/Unit/Models/Custom.php:402`）ので、公開側でも `@path` などが
     必ず生える。⚠ **エントリーのカスタムフィールドの経路は `$force` 無し**で
     `ACMS_POST` のときしか通らないので、同じ挙動だと思わないこと。

  ⚠ **写真が2枚そろわないときは器ごと出さない**（2枚を並べて見比べる形のため）。
     `:veil` はカスタムユニットで効かないので `BEGIN_IF [.../nem]` の入れ子で書く。

  ⚠ 縦位置（`@height > @width`）は `.beforeAfter_imgPortrait` を足してレターボックス。
-->




<!--
  目次ユニット。

  ✅ **2026-08-28 に develop テーマの Tailwind 版からカンプ版へ差し替えた。**
  出典: 「要約と目次のセット」（`275:47676`）の**下半分**。上半分の要約は
  **本文の外**（エントリーのカスタムフィールド `pageSummary`）。
    PC 帯   `I275:47676;5789:66271` index-title-close-01-pc
    PC 中身 `I275:47676;5789:66272` index01-pc
    SP      `275:96946` index-title-close-01-sp / `275:96947` index-title-open-01-sp
  ⚠ **`275:48003` / `275:48004` は別物**（それぞれ「引用-pc」「強調2（strong）pc」）。
    2026-08-28 に一度そう書いてしまい、レビューで実測により訂正した。
    **ノードIDは推測で書かず `get_metadata` で取ること。**
  ✅ SP の `275:96947`（開いた状態）は `expand_circle_down` を使っており、
    SCSS の「開くと下向き」の判断はカンプと一致している（同日実測）。
  静的コーディングは `static_html/base-detail.html` と `base-unit-parts.html`。

  ⚠⚠ **中身（ol / li / a）は書かない。** a-blog cms 同梱の document-outliner が
     `.js-outline`（＝ `.entry_body`）の見出しを走査して `.js-outline-yield` に
     流し込む。器だけを用意するのがこのユニットの役目。
     入力側の `data-*` はテンプレート（`include/pages/base-detail.twig` ほか）が
     持っている。アンカーは `data-anchorName="heading-$1"`、深さは
     `data-levelLimit="2"`（h2 と h3 だけ）。
     スタイルは `src/style/front/component/page-contents-index/`。

  ⚠⚠ **`data-listClassName` などを空にしても既定クラスは消えない**
     （2026-08-28 に実測で判明。それまでここに「空にしてあるので素の ol / li / a に
     なる」と書いてあったが**誤り**）。`src/js/lib/buildIn/document-outliner.js:28` の
     取り込みが `if (value)` で、**空文字は falsy なので上書きされず既定値が残る**。
     実際に出るのは

       <ol class="level-1 acms-ol"><li class="acms-ol-item">
         <a class="scrollTo" href="#heading-1">…

     ⚠ **見た目は壊れない。** `acms-ol` / `acms-ol-item` / `scrollTo` に当たる CSS は
     このテーマに1行も無く、スタイルは `level-1` / `level-2` と要素セレクタで
     組んであるため。**「素の ol / li / a が来る」を前提に SCSS を書き換えないこと。**
     🚩 `scrollTo` は a-blog cms 慣習のフッククラス（`js/config.js` の
     `scrollToMark: 'a.scrollTo'`）。**このテーマは今のところ何も紐付けていない**が、
     将来スムーススクロールを足すと目次のリンクだけ挙動が変わる。
     本当に素にしたいときは `src/js/main.js` の `documentOutliner(document)` に
     `` を渡す
     （`makeList` は `` の順なので
     options が既定に勝つ）。**全ての `.js-outline` に効くので影響範囲を見てから。**

  ⚠ **見出しが1つも無いエントリーでは器ごと消える。** 旧実装は Tailwind の
     `[&:not(:has(li))]:hidden` でやっていたが、クラスを外した以上 SCSS 側が
     同じ役目を持っている（`.pageContentsIndex:not(:has(li))`）。**外すと
     「目次」の帯だけが中身ゼロで出る。**

  ⚠ **`open` を消さないこと。** カンプは開いた状態。閉じた状態は
     `.pageContentsIndexToggle` が 90° 戻るだけで、初期値はこの属性が決める。

  ⚠ **開閉のアイコンは `expand_circle_right` 固定で、CSS が回している**
     （`.pageContentsIndex[open] ... `）。
     `.icon` はテキスト内容（リガチャ）でグリフが決まるため CSS で差し替えられない。
     ⚠ **`icon_fill` を付けないこと**（FILL 0。中は白抜き）。

  ⚠⚠ **開閉アニメーションのフックは `.pageContentsIndex` そのもの**
     （`src/js/component/details-accordion.js` の `ANIMATED_SELECTOR`）。
     `js-` 始まりのクラスは足さない —— 2026-08-26 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->











]]></description>
<category>福岡市内</category>
<guid isPermaLink="true">http://plaza-r.co.jp/event/fukuoka/lixil-fukuoka.html</guid>
<pubDate>Mon, 15 Dec 2025 13:33:49 +0900</pubDate>
</item>
</channel>
</rss>
