<?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/fukuoka/</link>
<atom:link href="http://plaza-r.co.jp/fukuoka/rss2.xml" rel="self" type="application/rss+xml" />
<language>ja</language>
<copyright>Copyright (C) 2026 福岡店 All rights reserved.</copyright>
<lastBuildDate>Sat, 04 Apr 2026 21:09:23 +0900</lastBuildDate>
<generator>a-blog cms</generator>
<docs>http://blogs.law.harvard.edu/tech/rss</docs>
<item>
<dc:creator>作業用アカウント</dc:creator>
<title>今年度もよろしくお願いいたします！</title>
<link>http://plaza-r.co.jp/fukuoka/blog/entry-13441.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">こんにちは！<br />
<br />
福岡店アドバイザーの内藤です。<br />
<br />
新年度が始まりましたね！<br />
私は、４月から３年目となりました。<br />
昨年度は多くのお客様との出会いや新しい経験などやりがいを感じながら仕事をすることができました！<br />
今年度もお客様に寄り添い、素敵な住まいづくりのお手伝いができるよう、精進してまいりますので、どうぞよろしくお願いいたします！！<br />
<br />
さて、本日は先月工事させていただきました、和室改装工事をご紹介いたします。<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 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->





























<!-- 画像 -->
<div class="column-image-left acms-col-sm-4">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/063/202604/2ef27f46cf3519b6c0b3e5d69415bd0f.jpg"
 alt=""
 width=""
 height="">
</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-left acms-col-sm-4">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/063/202604/fb26bff86fd499dfaec7b6178f83d363.jpg"
 alt=""
 width=""
 height="">
</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">リビングの一角に和室があるようなお部屋でした。<br />
こちらの和室を洋室へと改装して、書斎として使用したいというご相談がありました。<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 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->





























<!-- 画像 -->
<div class="column-image-left acms-col-sm-4">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/063/202604/f0b3009869be2a2e07b4e2a402cd2ae5.jpg"
 alt=""
 width=""
 height="">
</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-left acms-col-sm-4">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/063/202604/b54ff6d1fb97e2625bbd04473699c454.jpg"
 alt=""
 width=""
 height="">
</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-left acms-col-sm-4">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/063/202604/97d0a997689b75db35c72289ea1a6b22.jpg"
 alt=""
 width=""
 height="">
</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-left acms-col-sm-4">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/063/202604/58be7c9d50a7aee8940818b4752f1c5f.jpg"
 alt=""
 width=""
 height="">
</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">室内窓を取り付けることで、明かりや開放感が出ました。<br />
また、今回取付させていただいた、室内窓は360度回転するため、ご自身のお好みの開閉具合を調節できます。<br />
<br />
引戸に関しても、室内窓と統一感が出るようなデザインの商品を使用いたしました。<br />
押入部分も既存の押入の枠は利用して、折戸に変更し、枠の色を塗装することで、こちらも空間の統一感を演出する仕上りとなりました。<br />
<br />
お客様から素敵な仕上がりだと、おっしゃっていただけてとても嬉しかったです。<br />
<br />
お客様のご要望に合ったご提案をさせていただきますので、どうぞお気軽にご相談ください。<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 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->
























































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

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

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

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

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

<!--
  余白ユニット。

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

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

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

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

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


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

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

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

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

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

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

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

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


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

    <hr class="hr01" />

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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




<!--
  目次ユニット。

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

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

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

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

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

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

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

  ⚠ **開閉のアイコンは `expand_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>
<guid isPermaLink="true">http://plaza-r.co.jp/fukuoka/blog/entry-13441.html</guid>
<pubDate>Sat, 04 Apr 2026 21:09:30 +0900</pubDate>
</item>
<item>
<dc:creator>作業用アカウント</dc:creator>
<title>吉野　美咲</title>
<link>http://plaza-r.co.jp/fukuoka/staff/staffname-2155.html</link>
<description><![CDATA[


]]></description>
<guid isPermaLink="true">http://plaza-r.co.jp/fukuoka/staff/staffname-2155.html</guid>
<pubDate>Wed, 01 Apr 2026 11:59:59 +0900</pubDate>
</item>
<item>
<dc:creator>作業用アカウント</dc:creator>
<title>お花見ですね</title>
<link>http://plaza-r.co.jp/fukuoka/blog/entry-13433.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">お世話になります。<br />
福岡店、伊藤です。<br />
<br />
すっかり春めいてきまして、週末という事もあり福岡店のエリアでは、お花見の方がとてもたくさんいらっしゃいました。<br />
<br />
店舗の近くでは、冷泉公園。<br />
草香江のお客様のところへご訪問しましたが、こちらは、福岡さくらまつり。<br />
<br />
その他、様々な場所でみなさん楽しそうにしていました。<br />
<br />
私もお花見に行く予定ですが、定休日の火曜日は、、、雨予報、、、雨でも行きます。<br />
<br />
<br />
暖かくなってきますと、皆様リフォームのご検討が活発になってきます。<br />
今年も補助金がございますので、ぜひお得にリフォームができるよう、サポートさせていただきます。<br />
<br />
補助金申請は、面倒だな～というお声をいただきました。<br />
ご安心ください！すべて、弊社にて申請の対応をさせていただきます！<br />
<br />
詳しくは、4月4日(土)、5日(日)に開催します、TOTO相談会で、詳しくご説明をさせていただきます。<br />
気になるお客様は、ぜひご予約の上、ご来場ください。<br />
<br />
ご予約フォームはこちらです。<br />
https://www.housingplaza-net.co.jp/event-reservation/<br />
<br />
ご来場が、難しい方は、ご自宅にお伺いさせていただきますので、お気軽にお問い合わせをお願いいたします。<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>
<guid isPermaLink="true">http://plaza-r.co.jp/fukuoka/blog/entry-13433.html</guid>
<pubDate>Sun, 29 Mar 2026 19:23:02 +0900</pubDate>
</item>
<item>
<dc:creator></dc:creator>
<title>2026年補助額決定しました！</title>
<link>http://plaza-r.co.jp/fukuoka/blog/entry-13425.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">随分暖かくなりましたね＾＾<br />
<br />
過ごしやすい季節がやってきました。<br />
桜の開花ももう少し！<br />
<br />
そして、あっという間に年度末です…<br />
皆様お忙しい季節ではないでしょうか。<br />
今年度もきれいに仕事を締めくくり、気持ちよく来年度を迎えたいなと思います。<br />
<br />
まだまだ頑張ります！<br />
<br />
<br />
さて、今回は2026年度のリフォーム補助金のご紹介です。</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>
<guid isPermaLink="true">http://plaza-r.co.jp/fukuoka/blog/entry-13425.html</guid>
<pubDate>Mon, 23 Mar 2026 16:35:59 +0900</pubDate>
</item>
<item>
<dc:creator>作業用アカウント</dc:creator>
<title>寒い・・とお別れ</title>
<link>http://plaza-r.co.jp/fukuoka/blog/entry-13419.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">ようやく過ごしやすい季節になってきました。<br />
そろそろ桜も開花しそうで、春ですね！<br />
あっという間に夏が来ないことを祈ります。<br />
心配していた猫アレルギーはでませんでした、加茂です。<br />
こんにちは。<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 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->





























<!-- 画像 -->
<div class="column-image-center acms-col-sm-4">
<a href="http://plaza-r.co.jp/archives/063/202603/large-91620261c60448eba8745ee5d2a012e8.jpg"data-rel="SmartPhoto" data-caption="">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/063/202603/91620261c60448eba8745ee5d2a012e8.jpg"
 alt=""
 width="220"
 height="294">
</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 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->
























































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

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

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

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

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

<!--
  余白ユニット。

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

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

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

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

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


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

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

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

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

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

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

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

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


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

    <hr class="hr01" />

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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




<!--
  目次ユニット。

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

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

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

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

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

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

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

  ⚠ **開閉のアイコンは `expand_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>
<guid isPermaLink="true">http://plaza-r.co.jp/fukuoka/blog/entry-13419.html</guid>
<pubDate>Thu, 19 Mar 2026 17:21:29 +0900</pubDate>
</item>
<item>
<dc:creator>作業用アカウント</dc:creator>
<title>お風呂改装工事</title>
<link>http://plaza-r.co.jp/fukuoka/blog/entry-13412.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">こんにちは。<br />
福岡店工務の久木田です。<br />
<br />
少しずつ春の暖かさを感じる季節になってきましたが、<br />
まだ朝晩は冷え込む日もありますね。<br />
<br />
また、この時期は花粉に悩まされる方も多いのではないでしょうか。<br />
体調管理の難しい季節ですが、皆様いかがお過ごしでしょうか。<br />
<br />
今回はお風呂の改装工事の施工事例をご紹介させていただきます！<br />
<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>
<guid isPermaLink="true">http://plaza-r.co.jp/fukuoka/blog/entry-13412.html</guid>
<pubDate>Fri, 13 Mar 2026 19:31:24 +0900</pubDate>
</item>
<item>
<dc:creator>作業用アカウント</dc:creator>
<title>トイレ改装工事</title>
<link>http://plaza-r.co.jp/fukuoka/blog/entry-13407.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">こんにちは！<br />
福岡店の坂田です。<br />
<br />
<br />
3月に入り、朝晩は冷え込み、日中はポカポカ陽気と寒暖差が激しい時期になってきました。<br />
特にこの時期大変なのが、、、  花粉。<br />
今まで花粉症とは無縁でしたが、今年は鼻と目が痒くてたまりません(笑)<br />
皆様も万全な対策をして、今年の花粉を乗り切りましょう！<br />
<br />
さて、今回はトイレ改装工事の施工事例を紹介いたします。<br />
<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>
<guid isPermaLink="true">http://plaza-r.co.jp/fukuoka/blog/entry-13407.html</guid>
<pubDate>Mon, 09 Mar 2026 18:48:27 +0900</pubDate>
</item>
<item>
<dc:creator>作業用アカウント</dc:creator>
<title>木のぬくもり</title>
<link>http://plaza-r.co.jp/fukuoka/blog/entry-13400.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">こんにちは！<br />
福岡店アドバイザーの内藤です。<br />
<br />
花粉が気になる季節になってきましたね。皆様体調を崩されていませんか。<br />
<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 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->





























<!-- 画像 -->
<div class="column-image-center acms-col-sm-4">
<a href="http://plaza-r.co.jp/archives/063/202603/large-e4b21e19e2bcaa28ff1c4f6aee5291c7.jpg"data-rel="SmartPhoto" data-caption="">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/063/202603/e4b21e19e2bcaa28ff1c4f6aee5291c7.jpg"
 alt=""
 width="220"
 height="391">
</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/063/202603/large-45baeef3a2e02b1b566a65771e57b64b.jpg"data-rel="SmartPhoto" data-caption="">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/063/202603/45baeef3a2e02b1b566a65771e57b64b.jpg"
 alt=""
 width="340"
 height="192">
</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-4">
<a href="http://plaza-r.co.jp/archives/063/202603/large-9c8bd8a4e99b2edb94aadd114abfd6ce.jpg"data-rel="SmartPhoto" data-caption="">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/063/202603/9c8bd8a4e99b2edb94aadd114abfd6ce.jpg"
 alt=""
 width="220"
 height="391">
</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-4">
<a href="http://plaza-r.co.jp/archives/063/202603/large-b7550a1359500fbf2524560b28f51067.jpg"data-rel="SmartPhoto" data-caption="">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/063/202603/b7550a1359500fbf2524560b28f51067.jpg"
 alt=""
 width="220"
 height="391">
</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-4">
<a href="http://plaza-r.co.jp/archives/063/202603/large-69cf3b34dcfa8bedf67d3cf2a4d603f1.jpg"data-rel="SmartPhoto" data-caption="">
<img class="columnImage"
 src="http://plaza-r.co.jp/archives/063/202603/69cf3b34dcfa8bedf67d3cf2a4d603f1.jpg"
 alt=""
 width="220"
 height="294">
</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">今回のご自宅では、ワンちゃんや猫ちゃんを飼われており、お手入れや、空間を広くしたいということから、リフォームをご検討されておりました。<br />
<br />
まず、リビングと和室の間に合った間仕切襖は撤去し、リビングとの隔たりをなくし、広々とした空間をつくり出しました。<br />
そして、もともと敷居が入っていた部分にはフローリングを貼り、リビングのフローリングとの間には床見切といわれる部材を使用しております。<br />
<br />
今回、使用したフローリングは、天然木の突板のフローリングのため、木本来の木目やぬくもり、年数が経っていくにつれて、徐々にフローリングの顔も変化していく様子を楽しむことができます。<br />
また、抗菌、抗ウイルス、消臭効果などの機能性も高い商品になっております。<br />
もちろんワックスは不要なので、お手入れもしやすくなっております。<br />
<br />
ぜひリフォームをお考えの方は、細かな面までサポートさせていただきます！！<br />
また、今週末の3/7、3/8はキャナルシティ博多のTOTOSRにて相談会を行っておりますので、お気軽にご相談ください。<br />
社員一同、心よりお待ちしております。<br />
<br />
<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 に花田さんがこのクラス名を
     直接見る形で実装しており、**足しても効かず、名前を変えると黙って止まる。**
-->
























































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

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

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

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

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

<!--
  余白ユニット。

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

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

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

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

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


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

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

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

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

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

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

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

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


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

    <hr class="hr01" />

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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




<!--
  目次ユニット。

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

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

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

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

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

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

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

  ⚠ **開閉のアイコンは `expand_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>
<guid isPermaLink="true">http://plaza-r.co.jp/fukuoka/blog/entry-13400.html</guid>
<pubDate>Thu, 05 Mar 2026 09:09:55 +0900</pubDate>
</item>
<item>
<dc:creator>作業用アカウント</dc:creator>
<title>春めいてきましたね。</title>
<link>http://plaza-r.co.jp/fukuoka/blog/entry-13395.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">こんいちは。<br />
福岡店　伊藤です。<br />
<br />
最近は、日に日にあたたかくなってきています。<br />
それと同時に、花粉もひどくなってまして、くしゃみを連発しています。<br />
<br />
3月に入り、お客様がずいぶんと活発になってこられたように感じます。<br />
というのも、ご相談いただく件数が、ぐっと増えてたことと、OBのお客様からも<br />
お問い合わせを、よくいただいています。<br />
<br />
寒い間は、なかなかリフォームに踏み切れない方も多くいらっしゃいますので、<br />
気候の良い、春と秋は結構工事が混みあいます。<br />
おかげさまで、3月の工事予定はかなり埋まっておりますが、、、<br />
工事内容によっては、まだまだ対応させていただけますので、<br />
お急ぎの工事をお考えの方は、お気軽にご相談ください。<br />
<br />
今週末の、3月7日(土)・8日(日)は、毎月恒例のリフォーム相談会です。<br />
こちらも混みあう時間帯がございますので、ご予約をお願いいたします！<br />
スタッフ一同お待ちしております。<br />
<br />
ご予約フォームはこちら<br />
https://www.housingplaza-net.co.jp/event-reservation/</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>
<guid isPermaLink="true">http://plaza-r.co.jp/fukuoka/blog/entry-13395.html</guid>
<pubDate>Sun, 01 Mar 2026 18:44:50 +0900</pubDate>
</item>
<item>
<dc:creator></dc:creator>
<title>曲線を部屋に取り入れる</title>
<link>http://plaza-r.co.jp/fukuoka/blog/entry-13388.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">皆様、こんにちは！<br />
少しずつ春の訪れを感じられるようになってきましたね。<br />
もうすぐダウンやコートとおさらばできそうでうれしい限りです。<br />
ただまだ気温の変化が激しいので、くれぐれもご自愛くださいね。<br />
<br />
さて、先日、<br />
マンションの全面改装の工事を終え、お客様にお引き渡しさせていただいたのですが、<br />
お客様のこだわりの、かわいい内装仕上げを一部ご紹介させていただきます。<br />
全て工事中のお写真ですが、ご了承ください…m(_ _)m<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>
<guid isPermaLink="true">http://plaza-r.co.jp/fukuoka/blog/entry-13388.html</guid>
<pubDate>Mon, 23 Feb 2026 18:17:36 +0900</pubDate>
</item>
</channel>
</rss>
