diff --git a/templates/phase_z2/layouts/layouts.yaml b/templates/phase_z2/layouts/layouts.yaml
new file mode 100644
index 0000000..b2b234c
--- /dev/null
+++ b/templates/phase_z2/layouts/layouts.yaml
@@ -0,0 +1,130 @@
+# Phase Z 8-preset Layout Catalog
+#
+# User lock (2026-05-07) — Step 7-A:
+# Layout definitions migrated from hardcoded dict (src/phase_z2_composition.py
+# LAYOUT_PRESETS) to this catalog. Logic unchanged — backward compat
+# (load_layout_presets() returns same dict shape).
+#
+# Hierarchy:
+# slide_base (templates/phase_z2/slide_base.html)
+# -> layout (this catalog)
+# -> zone (positions)
+# -> frame family partial (templates/phase_z2/families/*.html)
+# -> slot payload
+#
+# Per-layout fields:
+# render_ready: bool
+# - true: layout has full grid definition + verified rendering path
+# - false: layout defined but render path incomplete (future-proof marker)
+# default_selection: bool
+# - true: select_layout_preset() picks this as default for matching unit_count
+# - false: defined alternative — not picked by current single-decision logic
+# (consumed by Step 7-B multiple-candidate generation, Step 9 fit eval)
+# candidate_when:
+# unit_count + optional signals (orientation / layout topology hint)
+# used by Step 7-B / Step 9 (currently inert — single-decision logic in
+# select_layout_preset() ignores this field).
+# unit_count = layout placement unit count (Step 4 output) =
+# raw section_count + promoted lead_orphans 등.
+
+single:
+ zones: 1
+ topology: single
+ positions: [primary]
+ css_areas: '"primary"'
+ css_cols: 1fr
+ css_rows: 1fr
+ render_ready: true
+ default_selection: true
+ candidate_when:
+ unit_count: 1
+
+horizontal-2:
+ zones: 2
+ topology: rows
+ positions: [top, bottom]
+ css_areas: '"top" "bottom"'
+ css_cols: 1fr
+ css_rows: 1fr 1fr
+ render_ready: true
+ default_selection: true
+ candidate_when:
+ unit_count: 2
+ orientation: horizontal
+
+vertical-2:
+ zones: 2
+ topology: cols
+ positions: [left, right]
+ css_areas: '"left right"'
+ css_cols: 1fr 1fr
+ css_rows: 1fr
+ render_ready: true
+ default_selection: false
+ candidate_when:
+ unit_count: 2
+ orientation: vertical
+
+top-1-bottom-2:
+ zones: 3
+ topology: T
+ positions: [top, bottom-left, bottom-right]
+ css_areas: '"top top" "bottom-left bottom-right"'
+ css_cols: 1fr 1fr
+ css_rows: 1fr 1fr
+ render_ready: true
+ default_selection: true
+ candidate_when:
+ unit_count: 3
+ layout: T
+
+top-2-bottom-1:
+ zones: 3
+ topology: inverted-T
+ positions: [top-left, top-right, bottom]
+ css_areas: '"top-left top-right" "bottom bottom"'
+ css_cols: 1fr 1fr
+ css_rows: 1fr 1fr
+ render_ready: true
+ default_selection: false
+ candidate_when:
+ unit_count: 3
+ layout: inverted-T
+
+left-1-right-2:
+ zones: 3
+ topology: side-T-left
+ positions: [left, right-top, right-bottom]
+ css_areas: '"left right-top" "left right-bottom"'
+ css_cols: 1fr 1fr
+ css_rows: 1fr 1fr
+ render_ready: true
+ default_selection: false
+ candidate_when:
+ unit_count: 3
+ layout: side-T-left
+
+left-2-right-1:
+ zones: 3
+ topology: side-T-right
+ positions: [left-top, right, left-bottom]
+ css_areas: '"left-top right" "left-bottom right"'
+ css_cols: 1fr 1fr
+ css_rows: 1fr 1fr
+ render_ready: true
+ default_selection: false
+ candidate_when:
+ unit_count: 3
+ layout: side-T-right
+
+grid-2x2:
+ zones: 4
+ topology: 2x2
+ positions: [top-left, top-right, bottom-left, bottom-right]
+ css_areas: '"top-left top-right" "bottom-left bottom-right"'
+ css_cols: 1fr 1fr
+ css_rows: 1fr 1fr
+ render_ready: true
+ default_selection: true
+ candidate_when:
+ unit_count: 4
diff --git a/templates/phase_z2/layouts/layouts_preview.html b/templates/phase_z2/layouts/layouts_preview.html
new file mode 100644
index 0000000..28cd0eb
--- /dev/null
+++ b/templates/phase_z2/layouts/layouts_preview.html
@@ -0,0 +1,121 @@
+
+
+
+
+Phase Z 8-preset Layout Catalog Preview
+
+
+
+
+Phase Z 8-preset Layout Catalog
+source: templates/phase_z2/layouts/layouts.yaml / 사람이 8 layout 시각 검증용. default selection = 현재 select_layout_preset() 단일 결정 로직에서 자동 선택. alternative = render_ready 이지만 자동 선택 안 됨 (Step 7-B 후보 활성화 대상).
+
+
+
+
+
single default selection
+
zones: 1 / topology: single / positions: [primary]
+
+
candidate_when: unit_count = 1
+
+
+
+
horizontal-2 default selection
+
zones: 2 / topology: rows / positions: [top, bottom]
+
+
candidate_when: unit_count = 2 / orientation = horizontal
+
+
+
+
vertical-2 alternative
+
zones: 2 / topology: cols / positions: [left, right]
+
+
candidate_when: unit_count = 2 / orientation = vertical
+
+
+
+
top-1-bottom-2 default selection
+
zones: 3 / topology: T / positions: [top, bottom-left, bottom-right]
+
+
top
+
bottom-left
+
bottom-right
+
+
candidate_when: unit_count = 3 / layout = T
+
+
+
+
top-2-bottom-1 alternative
+
zones: 3 / topology: inverted-T / positions: [top-left, top-right, bottom]
+
+
top-left
+
top-right
+
bottom
+
+
candidate_when: unit_count = 3 / layout = inverted-T
+
+
+
+
left-1-right-2 alternative
+
zones: 3 / topology: side-T-left / positions: [left, right-top, right-bottom]
+
+
left
+
right-top
+
right-bottom
+
+
candidate_when: unit_count = 3 / layout = side-T-left
+
+
+
+
left-2-right-1 alternative
+
zones: 3 / topology: side-T-right / positions: [left-top, right, left-bottom]
+
+
left-top
+
right
+
left-bottom
+
+
candidate_when: unit_count = 3 / layout = side-T-right
+
+
+
+
grid-2x2 default selection
+
zones: 4 / topology: 2x2 / positions: [top-left, top-right, bottom-left, bottom-right]
+
+
top-left
+
top-right
+
bottom-left
+
bottom-right
+
+
candidate_when: unit_count = 4
+
+
+
+
+
+
diff --git a/templates/phase_z2/regions/display_strategies.yaml b/templates/phase_z2/regions/display_strategies.yaml
new file mode 100644
index 0000000..33271e5
--- /dev/null
+++ b/templates/phase_z2/regions/display_strategies.yaml
@@ -0,0 +1,62 @@
+# Phase Z Display Strategy Catalog
+#
+# User lock (2026-05-07) — Step 8-A:
+# Display strategy vocabulary — how to present content within a region.
+# Source: docs/architecture/PHASE-Z-CONTENT-OBJECT-SUBZONE-SPEC.md (4 entry).
+#
+# Axis separation:
+# region_layouts.yaml = how to divide zone into regions (structure axis)
+# display_strategies.yaml (this file) = how to display content within region (policy axis)
+# The two axes are orthogonal — same region layout can use different strategies.
+#
+# Absolute user locks (must NOT be violated):
+# - Original text/table/image/details content is NEVER dropped or summarized.
+# - 오답노트 #5: 텍스트 압축 / trim / restructure 금지.
+# - IMPROVEMENT-REDESIGN.md line 110: "본문은 preview, 원문은 popup/detail 무손실 보존".
+# - "dropped" applies ONLY to decorative elements — strict forbidden_for enforcement.
+#
+# Per-entry fields:
+# description: str
+# applies_to: list[str] (content types that can use this strategy)
+# forbidden_for: list[str] (content types that MUST NOT use this strategy)
+# preserves_original: bool (true = original content kept somewhere — popup/detail)
+
+
+inline_full:
+ description: Content fully inline — entire content rendered within region.
+ applies_to: [text_block, table, image, details, decorative_element]
+ forbidden_for: []
+ preserves_original: true # all content is inline, original = inline
+
+
+inline_preview_with_details:
+ description: Partial inline preview + remaining content in details/popup.
+ applies_to: [text_block, table, details]
+ forbidden_for: [decorative_element]
+ preserves_original: true # User lock — original content kept in popup
+ detail_trigger:
+ placement: top-right # 본문 흐름 방해 X / 보조 동작 위치 / 안정 (user 2026-05-07)
+ label: details # identifier — display text 는 partial/UI 별 axis
+ preserves_original_note: "버튼은 원문 대체 X — 원문 전체 진입문"
+
+
+details_only:
+ description: Summary inline only, full content in popup.
+ applies_to: [text_block, table, details]
+ forbidden_for: [decorative_element]
+ preserves_original: true # User lock — full content in popup
+ detail_trigger:
+ placement: top-right # user lock — popup 진입 일관 위치
+ label: details
+ preserves_original_note: "버튼은 원문 대체 X — 원문 전체 진입문"
+
+
+dropped:
+ description: |
+ Decorative element omitted due to space constraints.
+ USER LOCK: applies ONLY to decorative_element.
+ NEVER drop text_block / table / image / details — original content preservation
+ is absolute (오답노트 #5, IMPROVEMENT-REDESIGN.md §3.6 line 110).
+ applies_to: [decorative_element]
+ forbidden_for: [text_block, table, image, details]
+ preserves_original: false # decorative only — no original to preserve
diff --git a/templates/phase_z2/regions/region_layouts.yaml b/templates/phase_z2/regions/region_layouts.yaml
new file mode 100644
index 0000000..8373744
--- /dev/null
+++ b/templates/phase_z2/regions/region_layouts.yaml
@@ -0,0 +1,95 @@
+# Phase Z Region Layout Catalog (Internal Region structure)
+#
+# User lock (2026-05-07) — Step 8-A:
+# Internal Region (= child zone) layout vocabulary catalog.
+# Source: docs/architecture/PHASE-Z-CONTENT-OBJECT-SUBZONE-SPEC.md §2.5 (v1, 6 entry).
+# Code connection (2026-05-08, Step 8-conn):
+# src/phase_z2_composition.py::load_region_layouts() reads this file.
+# src/phase_z2_pipeline.py step08 artifact records select_region_layout_candidates() output
+# per zone (placeholder signals: region_count=1, Step 3/4 부재 종속).
+# Step 9 v0 (application_plan) consumes the candidate list per unit.
+#
+# Hierarchy:
+# Slide -> Layout (slide-body zone 분배)
+# -> Zone -> Internal Region (this catalog) -> Frame -> Frame Slot -> Content
+#
+# Decision rule (SPEC §2.5 deterministic, AI X):
+# 1. region_count == 1 -> region-single
+# 2. details_presence == true / large content -> region-preview-details
+# 3. region_count == 4 AND 4 equal items -> region-grid-2x2
+# 4. region_count == 2 AND primary+supporting + ratio -> region-main-support
+# 5. region_count == 2 AND visual element (image/diagram)-> region-horizontal-split
+# 6. fallback -> region-vertical-stack
+#
+# Per-entry fields:
+# region_count: int | str (e.g. 1, 2, 4, "2+")
+# topology: vertical | horizontal | grid | weighted | preview-details | single
+# default_fallback: bool (true only for region-vertical-stack — SPEC §2.5)
+# description: str
+# candidate_when: dict (decision rule signals — Step 8-B input)
+
+
+region-single:
+ region_count: 1
+ topology: single
+ default_fallback: false
+ description: 1 region (zone entire = single region)
+ candidate_when:
+ region_count: 1
+
+
+region-vertical-stack:
+ region_count: "2+"
+ topology: vertical
+ default_fallback: true
+ description: Vertical top-bottom stack. Default fallback when no other rule matches.
+ candidate_when:
+ region_count_ge: 2
+ flow_type: sequential
+
+
+region-horizontal-split:
+ region_count: 2
+ topology: horizontal
+ default_fallback: false
+ description: Left-right horizontal split (text + image, text + diagram).
+ candidate_when:
+ region_count: 2
+ has_visual_element: true # image / diagram in content_type_mix
+
+
+region-main-support:
+ region_count: 2
+ topology: weighted
+ default_fallback: false
+ description: Main region + supporting region (asymmetric ratio, e.g. 0.7 / 0.3).
+ ratios_default: [0.7, 0.3]
+ candidate_when:
+ region_count: 2
+ role_pattern: primary_supporting
+ ratio_asymmetric: true # max / min >= 2
+
+
+region-preview-details:
+ region_count: 2
+ topology: preview-details
+ default_fallback: false
+ description: Inline preview region + details/popup region.
+ # preserves_original 은 display_strategies.yaml 의 책임 (axis 분리 lock 2026-05-07).
+ # User lock (원문 무손실 보존) 은 display_strategies 의 inline_preview_with_details
+ # / details_only 의 preserves_original: true 로 single source of truth 박힘.
+ candidate_when:
+ or:
+ - details_presence: true
+ - large_table: ">= 5 rows"
+ - long_text: true
+
+
+region-grid-2x2:
+ region_count: 4
+ topology: grid
+ default_fallback: false
+ description: 2x2 grid (4 equal regions).
+ candidate_when:
+ region_count: 4
+ flow_type: parallel_4
diff --git a/templates/phase_z2/regions/regions_preview.html b/templates/phase_z2/regions/regions_preview.html
new file mode 100644
index 0000000..36b20d4
--- /dev/null
+++ b/templates/phase_z2/regions/regions_preview.html
@@ -0,0 +1,166 @@
+
+
+
+
+Phase Z Child Zone / Internal Region Catalog Preview
+
+
+
+
+Phase Z Child Zone / Internal Region Catalog
+source: region_layouts.yaml + display_strategies.yaml / 사람이 두 axis (구조 + 정책) 시각 검증.
+SPEC: docs/architecture/PHASE-Z-CONTENT-OBJECT-SUBZONE-SPEC.md §2.5 (region 6 entry, display 4 entry)
+
+1. Region Layouts (zone 안 분할 구조 — 6 entry)
+
+
+
+
+
region-single 1 region
+
topology: single / region_count: 1
+
+
candidate_when: region_count = 1
+
+
+
+
region-vertical-stack default fallback
+
topology: vertical / region_count: 2+
+
+
region 1 (top)
+
region 2 (bottom)
+
+
candidate_when: region_count >= 2 AND flow_type = sequential. Default fallback when no other rule matches.
+
+
+
+
region-horizontal-split 2 region
+
topology: horizontal / region_count: 2 / has_visual_element: true
+
+
region 1 (left)
+
region 2 (right)
+
+
candidate_when: region_count = 2 AND visual element (image / diagram) in content_type_mix
+
+
+
+
region-main-support 2 region weighted
+
topology: weighted / ratios: [0.7, 0.3]
+
+
main (0.7)
+
support (0.3)
+
+
candidate_when: region_count = 2 AND role = [primary, supporting] AND ratio max/min >= 2
+
+
+
+
region-preview-details preview + popup
+
topology: preview-details / preserves_original: true
+
+
preview (inline)
+
details / popup
+
+
candidate_when: details_presence = true OR large_table (>=5 rows) OR long_text. User lock: 원문 무손실 보존.
+
+
+
+
region-grid-2x2 4 region
+
topology: grid / region_count: 4
+
+
region 1
+
region 2
+
region 3
+
region 4
+
+
candidate_when: region_count = 4 AND content type 4 equal items
+
+
+
+
+2. Display Strategies (콘텐츠 처리 정책 — 4 entry)
+
+
+
+
+
inline_full all content types
+
Content fully inline — entire content rendered within region.
+
applies_to: text_block table image details decorative_element
+
preserves_original: true (all inline = original is inline)
+
+
+
+
inline_preview_with_details popup preserved
+
Partial inline preview + remaining in details/popup. User lock: 원문 popup 보존.
+
applies_to: text_block table details
+
preserves_original: true (popup 안에 보존)
+
+
details
+
preview content (일부 inline)
+
preview content ...
+
+
detail_trigger: placement: top-right / label: details / 버튼은 원문 대체 X — 원문 전체 진입문
+
+
+
+
details_only popup preserved
+
Summary inline only, full content in popup. User lock: 전체 popup 보존.
+
applies_to: text_block table details
+
preserves_original: true (popup)
+
+
details
+
summary inline only
+
+
detail_trigger: placement: top-right / label: details / 전체 원문 popup 안 보존
+
+
+
+
dropped decorative only
+
Decorative element omitted due to space constraints.
+
applies_to: decorative_element
+
+ FORBIDDEN_FOR (절대 금지):
+ text_block table image details
+
+ User lock — 사용자 절대 룰. 텍스트 / 표 / 이미지 / details 콘텐츠는 절대 dropped X.
+ 오답노트 #5 / IMPROVEMENT-REDESIGN.md §3.6 line 110 — 원문 무손실 보존.
+
+
+
+
+
+
+
+