This commit is contained in:
@@ -0,0 +1,729 @@
|
||||
# Phase Z-2 frame contracts catalog (executable v0).
|
||||
#
|
||||
# 목적 :
|
||||
# Python mapper 에 박혀있던 slot 구조 / cardinality / visual role 을 catalog 로 끌어냄.
|
||||
# generic mapper (src/phase_z2_mapper.py:map_with_contract) 가 본 catalog 를 읽고
|
||||
# MdxSection → slot_payload 변환. frame 별 hand-coded mapper 를 제거 방향.
|
||||
#
|
||||
# 원칙 :
|
||||
# - frame 추가 = 본 yaml 에 entry 추가 (Python 수정은 새 builder/parser 필요시에만)
|
||||
# - role_order = 순서 기반 visual role (label 키워드 기반 X — 다른 MDX 도 깨지지 않게)
|
||||
# - cardinality strict 위반 → FitError → fallback path (AI restructuring 후보)
|
||||
# - payload.builder = PAYLOAD_BUILDERS named registry 의 entry
|
||||
# - builder 가 ITEM_PARSERS / COLUMN_BODY_PARSERS 같은 sub-primitive 호출
|
||||
#
|
||||
# v0 등록 frame :
|
||||
# F13 three_parallel_requirements → builder=items_with_role
|
||||
# F29 process_product_two_way → builder=process_product_pair
|
||||
# F16 bim_issues_quadrant_four → builder=quadrant_flat_slots
|
||||
# 이 셋이 현재 runtime 에서 실제 쓰는 주요 frame 의 모든 mapper.
|
||||
|
||||
three_parallel_requirements:
|
||||
template_id: three_parallel_requirements
|
||||
frame_id: 1171281190
|
||||
family: three_parallel
|
||||
|
||||
source_shape: top_bullets
|
||||
cardinality:
|
||||
strict: 3
|
||||
overflow_policy: abort_or_review
|
||||
|
||||
# 순서 기반 visual role (color_class 대체 — label 키워드 의존 제거)
|
||||
role_order:
|
||||
- tech
|
||||
- people
|
||||
- nature
|
||||
|
||||
# zone-level layout 힌트 — pipeline 의 compute_zone_layout 이 본 값을 lower bound 로 사용.
|
||||
# 230 = 본 frame 의 token-based font 기준 최소 가독 높이 (Figma → CSS adapt 검증값).
|
||||
visual_hints:
|
||||
min_height_px: 230
|
||||
|
||||
# NEW (SPEC v1 §3) : 본 frame 이 받을 수 있는 content_object type (Layer A → Layer B 매칭 입력).
|
||||
# 현재 mapper 는 본 필드를 *읽지 않음* — dormant. Layer A planner (B2) 가 도입 시 소비 예정.
|
||||
accepted_content_types:
|
||||
- text_block
|
||||
|
||||
# NEW (SPEC v1 §3) : Frame Slot (Layer B) 선언 — frame 내부 자리.
|
||||
# YAML field name 'sub_zones' = 코드/catalog reality 유지. 의미 = Frame Slot.
|
||||
# partial_target_path = path *식별자* 만 (값). 실제 marker attribute (data-frame-slot 등) 은 별 axis (B5).
|
||||
sub_zones:
|
||||
- id: pillar_1
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
partial_target_path: ".f13b__cols > .f13b__col:nth-child(1)"
|
||||
- id: pillar_2
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
partial_target_path: ".f13b__cols > .f13b__col:nth-child(2)"
|
||||
- id: pillar_3
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
partial_target_path: ".f13b__cols > .f13b__col:nth-child(3)"
|
||||
|
||||
payload:
|
||||
title:
|
||||
source: section.title
|
||||
builder: items_with_role
|
||||
builder_options:
|
||||
item_parser: pillar_item # ITEM_PARSERS entry
|
||||
array_root: pillars # payload[array_root] = list of items
|
||||
role_field: color_class # role_order[i] → item[role_field]
|
||||
|
||||
|
||||
process_product_two_way:
|
||||
template_id: process_product_two_way
|
||||
frame_id: 1171281210
|
||||
family: two_column_h3
|
||||
|
||||
source_shape: h3_subsections
|
||||
cardinality:
|
||||
strict: 2 # F29 frame = 2 visual columns. ≠2 → fallback.
|
||||
overflow_policy: abort_or_review
|
||||
|
||||
# transform-block + 3 sections 의 breathing 위해 345 (이전 hardcoded 동일).
|
||||
visual_hints:
|
||||
min_height_px: 345
|
||||
|
||||
# NEW (SPEC v1 §3) : 본 frame 이 받을 수 있는 content_object type.
|
||||
# process column 은 transform_table (AS-IS/TO-BE) 도 수용. product column 은 text_block 만.
|
||||
# 현재 mapper 는 본 필드를 *읽지 않음* — dormant.
|
||||
accepted_content_types:
|
||||
- text_block
|
||||
- transform_table
|
||||
|
||||
# NEW (SPEC v1 §3) : Frame Slot (Layer B) 선언.
|
||||
# 2 column × 3 section = 6 cell, but Frame Slot 단위 = column.
|
||||
# partial_target_path = path 식별자 만 (값). marker attribute 결정은 별 axis.
|
||||
sub_zones:
|
||||
- id: process_column
|
||||
role: main_text
|
||||
accepts: [text_block, transform_table]
|
||||
cardinality: { strict: 3 } # 3 sections per column
|
||||
partial_target_path: ".f29b__grid .f29b__cell--left"
|
||||
- id: product_column
|
||||
role: main_text
|
||||
accepts: [text_block] # product 쪽은 transform 안 받음 (현재 frame 의 시각 구분)
|
||||
cardinality: { strict: 3 }
|
||||
partial_target_path: ".f29b__grid .f29b__cell--right"
|
||||
|
||||
payload:
|
||||
title:
|
||||
source: section.title
|
||||
builder: process_product_pair
|
||||
builder_options:
|
||||
pad_sections_to: 3 # 각 column.sections 길이 = 3 (legacy 와 동일)
|
||||
columns:
|
||||
- title_to: banner_left
|
||||
body_to: process
|
||||
body_parser: column_with_transform # 첫 top-bullet AS-IS/TO-BE 표 인식
|
||||
- title_to: banner_right
|
||||
body_to: product
|
||||
body_parser: column_plain # 모든 section = 일반 text_lines
|
||||
|
||||
|
||||
bim_issues_quadrant_four:
|
||||
template_id: bim_issues_quadrant_four
|
||||
frame_id: 1171281193
|
||||
family: bim_issues_quadrant
|
||||
|
||||
source_shape: top_bullets
|
||||
# F16 정책 = pad_to=4 + truncate>4 (legacy 와 동일). cardinality strict 화는 본 transition 범위 외.
|
||||
# 향후 normal path 안정 후 strict 적용 + 위반 시 fallback path (FitError) 검토.
|
||||
|
||||
# NEW (SPEC v1 §3) : 본 frame 이 받을 수 있는 content_object type.
|
||||
# 현재 mapper 는 본 필드를 *읽지 않음* — dormant.
|
||||
accepted_content_types:
|
||||
- text_block
|
||||
|
||||
# NEW (SPEC v1 §3) : Frame Slot (Layer B) 선언 — 4 quadrant.
|
||||
# sub_zone 별 cardinality strict: 1 = 각 Frame Slot 의 *capacity* (Layer B schema).
|
||||
# 기존 payload.builder_options.pad_to=4 / truncate_at=4 = mapper runtime 거동 (input mismatch 시).
|
||||
# 두 layer 는 *공존* — 본 axis 에서 builder_options 는 미변경.
|
||||
sub_zones:
|
||||
- id: quadrant_1
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
partial_target_path: ".f16b__quadrant--tl"
|
||||
- id: quadrant_2
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
partial_target_path: ".f16b__quadrant--tr"
|
||||
- id: quadrant_3
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
partial_target_path: ".f16b__quadrant--bl"
|
||||
- id: quadrant_4
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
partial_target_path: ".f16b__quadrant--br"
|
||||
|
||||
payload:
|
||||
title:
|
||||
source: section.title
|
||||
builder: quadrant_flat_slots
|
||||
builder_options:
|
||||
item_parser: quadrant_item # ITEM_PARSERS entry
|
||||
pad_to: 4 # quadrant_1..4 모두 채움 (부족 시 empty pad)
|
||||
truncate_at: 4 # 5번째 이후 무시 + _truncated_count 기록
|
||||
label_key_pattern: "quadrant_{n}_label"
|
||||
body_key_pattern: "quadrant_{n}_body"
|
||||
empty_label: ""
|
||||
empty_body: []
|
||||
# implicit slot_order = [quadrant_1=TL, quadrant_2=TR, quadrant_3=BL, quadrant_4=BR]
|
||||
# 위치(TL/TR/BL/BR) 매핑은 partial template (families/bim_issues_quadrant_four.html) 결정.
|
||||
|
||||
|
||||
# ─── IMP-04 catalog 확장 (Gitea #4 scope-lock 7 frame) ───
|
||||
# 본 entry 들은 기존 3 entry (F13/F29/F16) *뒤에* append — YAML order 가
|
||||
# `list(load_frame_contracts().values())` 의 B4 trace 선택 순서 surface.
|
||||
# Reason 명시 (Codex Catch 5) : 각 frame 의 V4 use_as_is/light_edit 신호.
|
||||
|
||||
three_persona_benefits:
|
||||
# Reason : V4 use_as_is=1 (frame_number=14, frame_id=1171281191).
|
||||
# Pattern : cards-3col-persona (발주자/시공자/설계자 3 주체 각 benefit).
|
||||
template_id: three_persona_benefits
|
||||
frame_id: 1171281191
|
||||
family: cards
|
||||
|
||||
source_shape: top_bullets
|
||||
cardinality:
|
||||
strict: 3 # 3 persona = strict.
|
||||
overflow_policy: abort_or_review
|
||||
|
||||
# 순서 기반 color theme (Figma 원본 색).
|
||||
# client = 발주자 (#285b4a 그린 계열), constructor = 시공자 (#445a2f 올리브),
|
||||
# designer = 설계자 (#743002 적갈) — partial 의 .f14b__col--{role} 매핑.
|
||||
role_order:
|
||||
- client
|
||||
- constructor
|
||||
- designer
|
||||
|
||||
# min_height_px : derive + confirm (Codex round 13 §2.2 + round 24 asset 분류
|
||||
# + round 26 self-consistency catch + round 28 M1 결정).
|
||||
# Figma frame 1927 px @ scale 0.49213 → 948 px adapted (full frame).
|
||||
# Phase Z slide-body ≤ 585 px → adaptive content fit.
|
||||
# Content density 2nd refinement (raster promoted) :
|
||||
# badge raster 70 + bullet body 210 + photo strip 36 + padding 30 = 346 sum
|
||||
# + 4 safety buffer = **350** (F29 345 와 동등 class).
|
||||
# confirm via smoke harness `--render-to` artifact (browser visual inspection).
|
||||
visual_hints:
|
||||
min_height_px: 350
|
||||
|
||||
accepted_content_types:
|
||||
- text_block
|
||||
|
||||
# Frame Slot 선언 (SPEC v1 §3 layer B). 3 persona = 3 sub-zone.
|
||||
sub_zones:
|
||||
- id: persona_1
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
partial_target_path: ".f14b__cols > .f14b__col:nth-child(1)"
|
||||
- id: persona_2
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
partial_target_path: ".f14b__cols > .f14b__col:nth-child(2)"
|
||||
- id: persona_3
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
partial_target_path: ".f14b__cols > .f14b__col:nth-child(3)"
|
||||
|
||||
payload:
|
||||
title:
|
||||
source: section.title
|
||||
# builder 재사용 — F13 의 `items_with_role` + F16 의 `quadrant_item` parser.
|
||||
# quadrant_item = {label, body:[{text,indent}]} → persona card body 정합.
|
||||
builder: items_with_role
|
||||
builder_options:
|
||||
item_parser: quadrant_item # ITEM_PARSERS entry (F16 재사용)
|
||||
array_root: personas # payload.personas = list of items
|
||||
role_field: color_class # role_order[i] → item.color_class
|
||||
|
||||
|
||||
construction_goals_three_circle_intersection:
|
||||
# Reason : V4 use_as_is=1 (02-1) + light_edit=1 (01-1) + restructure=1 — UAI tier strongest.
|
||||
# Pattern : diagram / cycle-3way-intersection (3 메인 원 + 중앙 intersection).
|
||||
# Track A frame 2 / IMP-04 Track A V4 priority strict (Codex round 30/33/35 합의).
|
||||
template_id: construction_goals_three_circle_intersection
|
||||
frame_id: 1171281189
|
||||
family: diagram
|
||||
|
||||
source_shape: top_bullets
|
||||
cardinality:
|
||||
strict: 3 # 3 메인 원 — strict.
|
||||
overflow_policy: abort_or_review
|
||||
|
||||
# 순서 기반 visual role (3 메인 원 각자 다른 gradient — index.html L141-189).
|
||||
# circle_1 = 안전(orange/red), circle_2 = 생산성(brown/grey), circle_3 = 소통(green/dark).
|
||||
role_order:
|
||||
- safety
|
||||
- productivity
|
||||
- trust
|
||||
|
||||
# min_height_px derivation :
|
||||
# Figma frame total height = 1195 px @ scale 0.58312 → 697 px adapted (full frame).
|
||||
# Phase Z slide-body ≤ 585 px → compact adapted layout 필요.
|
||||
# Content density (3 메인 원 visual + title) — F14 (350, raster-heavy) 보다 가벼움.
|
||||
# Derived = 320 (3 원 60-80 px × 3 + title 30 + intersection 30 + padding 30).
|
||||
# Confirm via smoke `--render-to` artifact (R3 acceptance gate).
|
||||
visual_hints:
|
||||
min_height_px: 320
|
||||
|
||||
accepted_content_types:
|
||||
- text_block
|
||||
|
||||
# Frame Slot 선언 (SPEC v1 §3 layer B). 3 메인 원 + intersection center.
|
||||
sub_zones:
|
||||
- id: circle_1
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
partial_target_path: ".f12b__circles > .f12b__circle:nth-child(1)"
|
||||
- id: circle_2
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
partial_target_path: ".f12b__circles > .f12b__circle:nth-child(2)"
|
||||
- id: circle_3
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
partial_target_path: ".f12b__circles > .f12b__circle:nth-child(3)"
|
||||
- id: intersection
|
||||
role: emphasis
|
||||
accepts: [text_block]
|
||||
cardinality: { min: 0, max: 1 } # OPTIONAL — analysis.md "slots 5개, required 4개" 정합 (Codex F1-a 정정)
|
||||
partial_target_path: ".f12b__intersection"
|
||||
|
||||
payload:
|
||||
title:
|
||||
source: section.title
|
||||
# New builder `cycle_intersect_3` (phase_z2_mapper.py) — 3 circle labels + intersection.
|
||||
# parser 재사용 = `quadrant_item` (label 만 사용, body 무시).
|
||||
builder: cycle_intersect_3
|
||||
builder_options:
|
||||
item_parser: quadrant_item # F16 의 parser 재사용 (label only)
|
||||
pad_to: 3
|
||||
truncate_at: 3
|
||||
label_key_pattern: "circle_{n}_label"
|
||||
empty_label: ""
|
||||
intersection_default: "" # MDX 안 intersection 명시 안 되면 빈 문자
|
||||
|
||||
|
||||
construction_bim_three_usage:
|
||||
# Reason : V4 UAI=1 (01-1) + RS=1 — UAI tier strongest after F12.
|
||||
# Pattern : cards / cards-3-category — 3 horizontal stacked rows.
|
||||
# Track A frame 3 (Codex round 39 accepted, V4 priority strict).
|
||||
template_id: construction_bim_three_usage
|
||||
frame_id: 1171281182
|
||||
family: cards
|
||||
|
||||
source_shape: top_bullets
|
||||
cardinality:
|
||||
strict: 3
|
||||
overflow_policy: abort_or_review
|
||||
|
||||
# 순서 기반 visual role — 3 카테고리 (model / object / position) 각자
|
||||
# Figma 의 동일 brown label box + white content card 패턴. role 은
|
||||
# MDX label 내용 따라 결정되므로 generic ordering name 만.
|
||||
role_order:
|
||||
- category_1
|
||||
- category_2
|
||||
- category_3
|
||||
|
||||
# min_height_px derivation (round 13 §2.2 — derive + confirm) :
|
||||
# Figma frame 1066 px @ scale 0.67542 → 720 px adapted (full frame).
|
||||
# Phase Z compact (title + 3 rows + padding) :
|
||||
# title 30 + 3 row × 70 (label + body) + gap 6×2 + padding 30 = 282 px.
|
||||
# + safety buffer (body bullets 2-3 lines/row 보호) 38 = **320**.
|
||||
# Confirm via smoke `--render-to` artifact + MDX 03 regression.
|
||||
visual_hints:
|
||||
min_height_px: 320
|
||||
|
||||
accepted_content_types:
|
||||
- text_block
|
||||
|
||||
# Frame Slot 선언 (SPEC v1 §3 layer B). 3 category × {label + body}.
|
||||
sub_zones:
|
||||
- id: category_1
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
partial_target_path: ".f11b__rows > .f11b__row:nth-child(1)"
|
||||
- id: category_2
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
partial_target_path: ".f11b__rows > .f11b__row:nth-child(2)"
|
||||
- id: category_3
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
partial_target_path: ".f11b__rows > .f11b__row:nth-child(3)"
|
||||
|
||||
payload:
|
||||
title:
|
||||
source: section.title
|
||||
# Builder 재사용 = `quadrant_flat_slots` (F16) — pad_to / label_key / body_key
|
||||
# 만 configure. F16 / 본 frame 모두 *flat keyed slot + label + body* grammar.
|
||||
# Codex round 39 secondary builder reuse 허용 (V4 primary 보존).
|
||||
builder: quadrant_flat_slots
|
||||
builder_options:
|
||||
item_parser: quadrant_item # F16 의 parser 재사용
|
||||
pad_to: 3 # 3 categories
|
||||
truncate_at: 3
|
||||
label_key_pattern: "category_{n}_label"
|
||||
body_key_pattern: "category_{n}_body"
|
||||
empty_label: ""
|
||||
empty_body: []
|
||||
|
||||
|
||||
bim_dx_comparison_table:
|
||||
# Reason : V4 UAI=1 (01-2 "용어간 상호관계") — UAI tier strongest after F12/F11.
|
||||
# Pattern : table / compare-rows — 2-column compare table, N category rows.
|
||||
# Track A frame 4 (Codex round 41 accepted, V4 priority strict).
|
||||
# NEW builder `compare_table_2col` + NEW parser `compare_row_2col_item`.
|
||||
template_id: bim_dx_comparison_table
|
||||
frame_id: 1171281195
|
||||
family: table
|
||||
|
||||
source_shape: top_bullets
|
||||
# NOTE (Codex round 43 §F1-c) : top-level `cardinality.strict: 2` = *column 수*
|
||||
# (col_a / col_b). data row 수 는 별 — `sub_zones.rows.cardinality` 의 `{min:1, max:12}`.
|
||||
cardinality:
|
||||
strict: 2 # 2 columns (col_a / col_b) — NOT row count
|
||||
overflow_policy: abort_or_review
|
||||
|
||||
role_order:
|
||||
- col_a
|
||||
- col_b
|
||||
|
||||
# min_height_px derivation :
|
||||
# Figma frame compare table — N rows × ~40 px row height.
|
||||
# Phase Z compact (title 30 + header 30 + 6 data rows × 35 + padding 30) = 300
|
||||
# + safety buffer (longer cell content 보호) 50 = **350**. F14 와 동등 class.
|
||||
# Confirm via smoke + R3 artifact.
|
||||
visual_hints:
|
||||
min_height_px: 350
|
||||
|
||||
accepted_content_types:
|
||||
- text_block
|
||||
|
||||
# Frame Slot 선언 : header (col_a/col_b) + rows[].
|
||||
sub_zones:
|
||||
- id: col_a_header
|
||||
role: header
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
partial_target_path: ".f18b__header > .f18b__header-cell:nth-child(2)"
|
||||
- id: col_b_header
|
||||
role: header
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
partial_target_path: ".f18b__header > .f18b__header-cell:nth-child(3)"
|
||||
- id: rows
|
||||
role: data
|
||||
accepts: [text_block]
|
||||
cardinality: { min: 1, max: 12 } # N category rows (typical 4-8)
|
||||
partial_target_path: ".f18b__rows"
|
||||
|
||||
payload:
|
||||
title:
|
||||
source: section.title
|
||||
# NEW builder `compare_table_2col` (phase_z2_mapper.py) +
|
||||
# NEW parser `compare_row_2col_item` (ITEM_PARSERS).
|
||||
builder: compare_table_2col
|
||||
builder_options:
|
||||
item_parser: compare_row_2col_item # NEW parser — top_bullet → {label, col_a, col_b}
|
||||
col_a_label_default: "BIM" # F1-a (Codex round 43) — explicit default
|
||||
col_b_label_default: "DX" # F1-a — explicit default
|
||||
strip_col_prefix_aliases: # F1-b (Codex round 43) — narrow alias 만 strip
|
||||
- "BIM"
|
||||
- "DX"
|
||||
max_rows: 12 # typical 4-8, overflow 보호
|
||||
|
||||
|
||||
dx_sw_necessity_three_perspectives:
|
||||
# Reason : V4 LE=2 (03-1 + 01-1) + RS=1 — V4 LE tier strongest 잔여.
|
||||
# Pattern : cards / cards-3-header — 3 columns horizontal (DX 필수성 3 관점).
|
||||
# Track A frame 5 (Codex round 45 accepted, V4 priority strict).
|
||||
# builder 재사용 = `quadrant_flat_slots` (F16/F11 pattern). 새 builder/parser 0.
|
||||
template_id: dx_sw_necessity_three_perspectives
|
||||
frame_id: 1171281198
|
||||
family: cards
|
||||
|
||||
source_shape: top_bullets
|
||||
cardinality:
|
||||
strict: 3 # 3 perspective columns
|
||||
overflow_policy: abort_or_review
|
||||
|
||||
# 순서 기반 role naming (3 perspective 각자 color 도 다를 수 있음 — 단순 ordering).
|
||||
role_order:
|
||||
- perspective_1
|
||||
- perspective_2
|
||||
- perspective_3
|
||||
|
||||
# min_height_px derivation :
|
||||
# 3 column × (header 30 + body bullets ~3 × 25) + title 30 + padding 30 = ~ 195.
|
||||
# safety buffer (label 길고 body 5+ bullets 보호) = 125 → **320**.
|
||||
# F12/F11/F18 와 동등 class. confirm via smoke + R3.
|
||||
visual_hints:
|
||||
min_height_px: 320
|
||||
|
||||
accepted_content_types:
|
||||
- text_block
|
||||
|
||||
# Frame Slot 선언 : 3 perspective columns (각 column = label + body).
|
||||
sub_zones:
|
||||
- id: perspective_1
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
partial_target_path: ".f20b__cols > .f20b__col:nth-child(1)"
|
||||
- id: perspective_2
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
partial_target_path: ".f20b__cols > .f20b__col:nth-child(2)"
|
||||
- id: perspective_3
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
partial_target_path: ".f20b__cols > .f20b__col:nth-child(3)"
|
||||
|
||||
payload:
|
||||
title:
|
||||
source: section.title
|
||||
# Builder 재사용 = `quadrant_flat_slots` (F16/F11 pattern).
|
||||
# 새 builder / 새 parser 0. F18 같은 새 builder 도입 아님 (Codex round 45 secondary reuse 허용).
|
||||
builder: quadrant_flat_slots
|
||||
builder_options:
|
||||
item_parser: quadrant_item # F16/F11 의 parser 재사용
|
||||
pad_to: 3 # 3 perspectives
|
||||
truncate_at: 3
|
||||
label_key_pattern: "perspective_{n}_label"
|
||||
body_key_pattern: "perspective_{n}_body"
|
||||
empty_label: ""
|
||||
empty_body: []
|
||||
|
||||
|
||||
info_management_what_how_when:
|
||||
# Reason : V4 신호 0 (4 MDX sample 안). 32-frame all-in scope 채우는
|
||||
# **catalog-completeness activation** (NOT V4 endorsement, Codex round 47 guardrail).
|
||||
# V4 는 matching authority. 향후 다른 MDX section 에서 V4 가 이 frame 을 추천 시
|
||||
# backend 가 받을 수 있도록 등록.
|
||||
# Pattern : cards/3-section-framework (What/How/When 3 관점 framework).
|
||||
# Track A frame 6. Builder 재사용 = `quadrant_flat_slots` (F11/F20 pattern).
|
||||
template_id: info_management_what_how_when
|
||||
frame_id: 1171281179
|
||||
family: cards
|
||||
|
||||
source_shape: top_bullets
|
||||
cardinality:
|
||||
strict: 3 # 3 sections (What / How / When)
|
||||
overflow_policy: abort_or_review
|
||||
|
||||
role_order:
|
||||
- section_1 # What (무슨 정보)
|
||||
- section_2 # How (어떻게 연계)
|
||||
- section_3 # When (언제 사용)
|
||||
|
||||
# min_height_px : F20 와 동등 (3-column body + header). 320 = 3×(header 30 +
|
||||
# body bullets 75) + title 30 + padding 30 + buffer 125 / 195 base.
|
||||
visual_hints:
|
||||
min_height_px: 320
|
||||
|
||||
accepted_content_types:
|
||||
- text_block
|
||||
|
||||
sub_zones:
|
||||
- id: section_1
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
partial_target_path: ".f8b__cols > .f8b__col:nth-child(1)"
|
||||
- id: section_2
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
partial_target_path: ".f8b__cols > .f8b__col:nth-child(2)"
|
||||
- id: section_3
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
partial_target_path: ".f8b__cols > .f8b__col:nth-child(3)"
|
||||
|
||||
payload:
|
||||
title:
|
||||
source: section.title
|
||||
builder: quadrant_flat_slots # 재사용 (F16/F11/F20 pattern)
|
||||
builder_options:
|
||||
item_parser: quadrant_item # 재사용
|
||||
pad_to: 3
|
||||
truncate_at: 3
|
||||
label_key_pattern: "section_{n}_label"
|
||||
body_key_pattern: "section_{n}_body"
|
||||
empty_label: ""
|
||||
empty_body: []
|
||||
|
||||
|
||||
sw_reality_three_emphasis:
|
||||
# Reason : V4 신호 0 (4 MDX sample). 32-frame all-in scope
|
||||
# **catalog-completeness activation** (NOT V4 endorsement, Codex round 49 §1+§2).
|
||||
# Pattern : cards / title-plus-3-emphasis — 3 problem-emphasis cards parallel.
|
||||
# Track A frame 7 (single-frame, Codex round 49 §9 — no batch yet).
|
||||
# Builder 재사용 = `quadrant_flat_slots` (F11/F20/F8 pattern).
|
||||
template_id: sw_reality_three_emphasis
|
||||
frame_id: 1171281209
|
||||
family: cards
|
||||
|
||||
source_shape: top_bullets
|
||||
cardinality:
|
||||
strict: 3
|
||||
overflow_policy: abort_or_review
|
||||
|
||||
role_order:
|
||||
- emphasis_1
|
||||
- emphasis_2
|
||||
- emphasis_3
|
||||
|
||||
visual_hints:
|
||||
min_height_px: 320
|
||||
|
||||
accepted_content_types:
|
||||
- text_block
|
||||
|
||||
sub_zones:
|
||||
- id: emphasis_1
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
partial_target_path: ".f28b__cols > .f28b__col:nth-child(1)"
|
||||
- id: emphasis_2
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
partial_target_path: ".f28b__cols > .f28b__col:nth-child(2)"
|
||||
- id: emphasis_3
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
partial_target_path: ".f28b__cols > .f28b__col:nth-child(3)"
|
||||
|
||||
payload:
|
||||
title:
|
||||
source: section.title
|
||||
builder: quadrant_flat_slots # 재사용
|
||||
builder_options:
|
||||
item_parser: quadrant_item # 재사용
|
||||
pad_to: 3
|
||||
truncate_at: 3
|
||||
label_key_pattern: "emphasis_{n}_label"
|
||||
body_key_pattern: "emphasis_{n}_body"
|
||||
empty_label: ""
|
||||
empty_body: []
|
||||
|
||||
|
||||
bim_current_problems_paired:
|
||||
# Reason : V4 RS=1 (4 MDX sample 안 restructure 1). source 가 8 atomic issues 임을 confirm.
|
||||
# **schema-correction** — round 55~73 의 review-loop 의 calibration frame.
|
||||
# 자체 round 71 §4 F17 done-definition lock per Codex round 70/72 + Claude round 63 §5.
|
||||
# Pattern : cards/paired-rows-4x2 — 4 paired rows × 2 issue cells (top/bottom pill alternation).
|
||||
# Track A frame 8. 신규 builder = `paired_rows_4x2_slots` (quadrant_flat_slots → 2-axis).
|
||||
template_id: bim_current_problems_paired
|
||||
frame_id: 1171281194
|
||||
family: cards
|
||||
|
||||
source_shape: top_bullets # mapper split_source allow-list 정합 (Codex round 60)
|
||||
layout_variant: paired_rows_4x2_alternating_pills # runtime projection model
|
||||
cardinality:
|
||||
strict: 8 # 8 atomic issues (4 rows × 2 cells per source texts.md)
|
||||
overflow_policy: abort_or_review
|
||||
|
||||
# row × side deterministic mapping per Codex round 70 §1.
|
||||
role_order:
|
||||
- row_1_left
|
||||
- row_1_right
|
||||
- row_2_left
|
||||
- row_2_right
|
||||
- row_3_left
|
||||
- row_3_right
|
||||
- row_4_left
|
||||
- row_4_right
|
||||
|
||||
# min_height_px : provisional 380 (8 cells + title + gaps), smoke 후 1 회 조정 가능.
|
||||
# pill_positions : source index.html line 161~225 의 row-별 pill 상/하 alternation (top/bottom/top/bottom).
|
||||
# row_gap_after : source line 199-200 의 `<div class="row-gap">` (행 2-3 사이 시각 단락) per Codex round 58 §3.
|
||||
visual_hints:
|
||||
min_height_px: 380
|
||||
pill_positions: [top, bottom, top, bottom]
|
||||
row_gap_after: [2]
|
||||
|
||||
accepted_content_types:
|
||||
- text_block
|
||||
|
||||
sub_zones:
|
||||
- id: row_1_left
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
partial_target_path: ".f17b__row:nth-child(1) > .f17b__cell--left"
|
||||
- id: row_1_right
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
partial_target_path: ".f17b__row:nth-child(1) > .f17b__cell--right"
|
||||
- id: row_2_left
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
partial_target_path: ".f17b__row:nth-child(2) > .f17b__cell--left"
|
||||
- id: row_2_right
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
partial_target_path: ".f17b__row:nth-child(2) > .f17b__cell--right"
|
||||
- id: row_3_left
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
partial_target_path: ".f17b__row:nth-child(3) > .f17b__cell--left"
|
||||
- id: row_3_right
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
partial_target_path: ".f17b__row:nth-child(3) > .f17b__cell--right"
|
||||
- id: row_4_left
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
partial_target_path: ".f17b__row:nth-child(4) > .f17b__cell--left"
|
||||
- id: row_4_right
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
partial_target_path: ".f17b__row:nth-child(4) > .f17b__cell--right"
|
||||
|
||||
payload:
|
||||
title:
|
||||
source: section.title
|
||||
# 신규 builder — quadrant_flat_slots 와 차이 : 1-axis (TL/TR/BL/BR) → 2-axis (row × side).
|
||||
# strict 8 + no pad/truncate (silent loss 차단, Codex round 60 §3).
|
||||
# parser = quadrant_item 재사용 (label + body heading-less, Codex round 60).
|
||||
builder: paired_rows_4x2_slots
|
||||
builder_options:
|
||||
item_parser: quadrant_item
|
||||
label_key_pattern: "row_{r}_{side}_label"
|
||||
body_key_pattern: "row_{r}_{side}_body"
|
||||
rows: 4
|
||||
sides: [left, right]
|
||||
@@ -0,0 +1,37 @@
|
||||
# Phase Z Families — WIP Marker
|
||||
|
||||
**Status:** intentionally untracked, uncontracted, out-of-scope for runtime matcher.
|
||||
**Closes audit follow-up:** INTEGRATION-AUDIT-01-REPORT.md §10.2 F-2 (option c).
|
||||
**Gate for promote/remove:** Gitea issue #42 (`IMP-04b Catalog extension to 32 frames`).
|
||||
|
||||
## Baseline lock (2026-05-19)
|
||||
|
||||
| Surface | Count | Notes |
|
||||
|---|---|---|
|
||||
| `git ls-files templates/phase_z2/families/*.html` | 11 | tracked family templates |
|
||||
| `templates/phase_z2/catalog/frame_contracts.yaml` top-level keys | 11 | 1:1 with tracked basenames |
|
||||
| `Get-ChildItem templates/phase_z2/families/*.html` | 13 | tracked 11 + WIP 2 (below) |
|
||||
|
||||
Active contracted family count = **11**. Tracked basenames ↔ `frame_contracts.yaml` top-level keys are set-equal. Drift between disk (13) and contracted (11) is fully explained by the 2 WIP files below.
|
||||
|
||||
## WIP family templates (uncontracted)
|
||||
|
||||
| File | Figma frame | Status |
|
||||
|---|---|---|
|
||||
| `app_sw_package_vs_solution.html` | frame 23 (`1171281203`) | WIP — not in `frame_contracts.yaml`, not in runtime matcher set. |
|
||||
| `pre_construction_model_info_stacked.html` | frame 9 (`1171281180`) | WIP — not in `frame_contracts.yaml`, not in runtime matcher set. |
|
||||
|
||||
These files are partials authored during Phase Z-2 MVP-1.5b exploration. They are **not** part of the contracted Phase Z runtime catalog and must not be enumerated by frame selection, matcher, or any Stage 3 pipeline surface.
|
||||
|
||||
## Rules
|
||||
|
||||
- Adding a file to `templates/phase_z2/families/*.html` without a matching `frame_contracts.yaml` entry is **only** permitted if it is named here as WIP.
|
||||
- `tests/test_family_contract_baseline.py` enforces this invariant: tracked families ↔ `frame_contracts.yaml` keys must be set-equal, modulo the WIP allowlist parsed from this file.
|
||||
- Promoting a WIP file (add `frame_contracts.yaml` entry + register with matcher) or removing it must happen under issue #42 or a follow-up issue, not silently.
|
||||
|
||||
## References
|
||||
|
||||
- `docs/architecture/INTEGRATION-AUDIT-01-REPORT.md` §10.2 F-2 (audit finding closed by issue #52, option c)
|
||||
- `docs/architecture/IMP-18-SVG-GAP-REPORT.md` L28, L51 (count basis corrected to `11 contracted + 2 WIP`)
|
||||
- Gitea issue #52 (this reconciliation)
|
||||
- Gitea issue #42 (pre-flight gate for promote/remove)
|
||||
@@ -0,0 +1,159 @@
|
||||
<!-- Phase Z-2 MVP F17 schema-correction partial — paired_rows_4x2_alternating_pills.
|
||||
§17 룰 — Figma 시각 언어 promote, geometry 만 zone-compatible adapt.
|
||||
본 partial = round 55~73 review-loop 의 calibration frame implementation. -->
|
||||
{#
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
Frame 17 = "현황 및 문제점" (cards/paired-rows-4x2-alternating-pills).
|
||||
**source = 8 atomic issues** (4 paired rows × 2 issue cells per row).
|
||||
이전 strict-4 → source 의 절반 누락. round 55~73 review-loop 의 schema-correction.
|
||||
|
||||
Visual provenance — figma_to_html_agent/blocks/1171281194/{index.html, texts.md, assets}.
|
||||
- title gradient : rgb(204,82,0) → rgb(136,55,0) (source line 50)
|
||||
- row border : 3px solid #60A451 (source line 69)
|
||||
- row bg : rgba(250,237,203,0.15) (source line 68)
|
||||
- body text : #0c271e (source line 130)
|
||||
- 분할선 (cell 사이) : 2px dashed #60A451 (source line 135)
|
||||
- pill alternation : row 1/3 = pill 상단, row 2/4 = pill 하단 (source line 161~225)
|
||||
- row 2-3 visual gap : source `<div class="row-gap">` (height 65px) line 199-200
|
||||
|
||||
PROMOTED CSS : source-faithful unified green/cream/brown theme + pill shape +
|
||||
top/bottom/top/bottom pill alternation + row 2-3 visual gap.
|
||||
|
||||
NOT PROMOTED (scope cap per Codex round 64/72 — CSS fallback 정당) :
|
||||
- pill asset crop variant (`.crop-left` left -45.3% width 145.3% / `.crop-right` width 151.25%) —
|
||||
source 의 PNG asset 정확 crop reproduction 은 single-pass scope 외 (Codex round 62 §6
|
||||
+ round 68 scope cap). CSS approximation = pill shape + alternation + theme 모두 보존.
|
||||
- bottom pill flip image transform (source line 117) — 단순 column-reverse 로 처리.
|
||||
|
||||
ADAPTED : Figma absolute → 4-row flex layout + token-fixed typography.
|
||||
|
||||
slots (17) : title +
|
||||
row_{1..4}_{left,right}_{label,body} (8 × 2 = 16).
|
||||
|
||||
no row headers (source 부재, infer 금지 per Codex round 58 §1 + round 70 §3.6).
|
||||
#}
|
||||
|
||||
<style>
|
||||
.f17b {
|
||||
width: 100%; height: 100%;
|
||||
display: flex; flex-direction: column;
|
||||
gap: 8px;
|
||||
font-family: 'Noto Sans KR', 'Pretendard', sans-serif;
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
/* title — source line 50 gradient + drop-shadow (text-shadow approximation) */
|
||||
.f17b__title {
|
||||
font-size: var(--font-zone-title);
|
||||
font-weight: 700;
|
||||
line-height: var(--lh-zone-title);
|
||||
background-image: linear-gradient(rgb(204,82,0), rgb(136,55,0));
|
||||
-webkit-background-clip: text; background-clip: text;
|
||||
color: transparent;
|
||||
flex-shrink: 0;
|
||||
filter: drop-shadow(0 0 3px rgba(50,44,30,0.4));
|
||||
}
|
||||
|
||||
/* rows 컨테이너 (4 paired rows) */
|
||||
.f17b__rows {
|
||||
display: flex; flex-direction: column;
|
||||
gap: 4px;
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
/* row 2 뒤 visual gap (visual_hints.row_gap_after = [2]) — source line 199-200 */
|
||||
.f17b__row:nth-child(2) { margin-bottom: 10px; }
|
||||
|
||||
/* row = 좌우 2 cells flex */
|
||||
.f17b__row {
|
||||
display: flex; flex-direction: row;
|
||||
gap: 6px;
|
||||
flex: 1 1 0;
|
||||
min-height: 0;
|
||||
border: 2px solid #60A451;
|
||||
border-radius: 8px;
|
||||
background: rgba(250,237,203,0.15);
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* cell — pill alternation per visual_hints.pill_positions [top,bottom,top,bottom] */
|
||||
.f17b__cell {
|
||||
flex: 1 1 0;
|
||||
display: flex; flex-direction: column;
|
||||
padding: 8px 10px;
|
||||
min-width: 0;
|
||||
gap: 4px;
|
||||
}
|
||||
/* 분할선 — source line 135 dashed 2px #60A451 (cell 사이) */
|
||||
.f17b__cell--right { border-left: 2px dashed #60A451; }
|
||||
|
||||
/* row 1, 3 = pill 상단 (default column) */
|
||||
.f17b__row:nth-child(1) .f17b__cell,
|
||||
.f17b__row:nth-child(3) .f17b__cell { flex-direction: column; }
|
||||
/* row 2, 4 = pill 하단 (column-reverse — pill 이미지 flip 은 단순 reverse 로 approximate per source line 117) */
|
||||
.f17b__row:nth-child(2) .f17b__cell,
|
||||
.f17b__row:nth-child(4) .f17b__cell { flex-direction: column-reverse; }
|
||||
|
||||
/* pill — CSS approximation (source assets/*.png crop variant fallback per round 64/72 scope cap).
|
||||
pill shape (rounded) + green/cream/brown theme 보존. */
|
||||
.f17b__pill {
|
||||
display: inline-flex; align-items: center; justify-content: center;
|
||||
background-image: linear-gradient(180deg, #60A451 0%, #3d6d34 100%);
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
font-size: var(--font-sub-title);
|
||||
line-height: 1.15;
|
||||
padding: 4px 14px;
|
||||
border-radius: 999px;
|
||||
text-align: center;
|
||||
flex-shrink: 0;
|
||||
letter-spacing: -0.02em;
|
||||
align-self: flex-start;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.15);
|
||||
}
|
||||
|
||||
/* body — source line 130 color #0c271e */
|
||||
.f17b__body {
|
||||
flex: 1 1 auto;
|
||||
overflow: hidden;
|
||||
color: #0c271e;
|
||||
min-height: 0;
|
||||
display: flex; flex-direction: column;
|
||||
gap: 2px;
|
||||
}
|
||||
.f17b__body .text-line {
|
||||
color: inherit;
|
||||
font-size: var(--font-body);
|
||||
line-height: var(--lh-body);
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="f17b" data-frame-id="1171281194" data-template-id="bim_current_problems_paired">
|
||||
<div class="f17b__title">{{ slot_payload.title }}</div>
|
||||
<div class="f17b__rows">
|
||||
{% for r in [1, 2, 3, 4] %}
|
||||
<div class="f17b__row">
|
||||
<div class="f17b__cell f17b__cell--left">
|
||||
<div class="f17b__pill">{{ slot_payload['row_' ~ r ~ '_left_label'] | safe }}</div>
|
||||
<div class="f17b__body">
|
||||
{% set body_left = slot_payload['row_' ~ r ~ '_left_body'] %}
|
||||
{% if body_left %}
|
||||
{% for line in body_left %}<div class="text-line{% if line.indent and line.indent > 0 %} text-line--indent-{{ line.indent }}{% endif %}">{{ line.text | safe }}</div>{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="f17b__cell f17b__cell--right">
|
||||
<div class="f17b__pill">{{ slot_payload['row_' ~ r ~ '_right_label'] | safe }}</div>
|
||||
<div class="f17b__body">
|
||||
{% set body_right = slot_payload['row_' ~ r ~ '_right_body'] %}
|
||||
{% if body_right %}
|
||||
{% for line in body_right %}<div class="text-line{% if line.indent and line.indent > 0 %} text-line--indent-{{ line.indent }}{% endif %}">{{ line.text | safe }}</div>{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,146 @@
|
||||
<!-- Phase Z-2 MVP-1.5b frame-derived adapted block.
|
||||
§17 룰 — Figma 시각 언어 promote, geometry 만 zone-compatible adapt. -->
|
||||
{#
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
Visual Provenance — figma_to_html_agent/blocks/1171281195/ (frame 18)
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
Frame 18 = "BIM 과 DX 의 이해" (table / compare-rows). 2개 column header (BIM vs DX) +
|
||||
중앙 category column + N category rows (범위 / S/W / 프로세스 / 성과물 / 활용 /
|
||||
확장성 / 수행개념 / 주체 등). compare 관점의 다면 비교 표 디자인.
|
||||
|
||||
본 partial = Track A frame 4 (Codex round 41 accepted, V4 UAI tier). NEW builder
|
||||
`compare_table_2col` + NEW parser `compare_row_2col_item` 도입.
|
||||
|
||||
3-layer architecture (matrix §0) :
|
||||
- V4 = matching authority — V4 ranked this frame use_as_is for 01-2.
|
||||
- figma_to_html = source/evidence — analysis/texts/index.html/flat/assets full.
|
||||
- Phase Z = runtime orchestration — 본 commit 추가 runtime 자원.
|
||||
|
||||
PROMOTED — CSS :
|
||||
- title gradient (#000 → #883700, F13/F14/F12/F11 zone-title family)
|
||||
- header row : col_a/col_b background tint + bold typography
|
||||
- row 별 alternating background (zebra) — readability ↑
|
||||
- cell border : subtle divider (#A5BBB4 family — F11 와 통일)
|
||||
|
||||
NOT PROMOTED (P1 case-by-case, compact zone fit) :
|
||||
- Figma 의 column header 의 *raster icon* (있는 경우) — compact 에서 효과 ↓
|
||||
- 다양한 색 강조 / 한자 deco (Figma source 보존, 미 promote)
|
||||
|
||||
ADAPTED :
|
||||
- Figma 표 absolute positioning + zoom → Phase Z flex/grid (3-column table)
|
||||
- typography → token-fixed (zone-title / sub-title / caption / body)
|
||||
- row 별 height auto (content-fit)
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
min_height_px derivation :
|
||||
title 30 + header 30 + 6 data rows × 35 (compact) + padding 30 = 300
|
||||
+ safety buffer (longer cell content) 50 = **350** (F14 와 동등 class).
|
||||
Confirm via smoke + R3 artifact + V4 use_as_is target sample (MDX 01-2 미 trigger
|
||||
in MDX 03 regression, 단 future batch verification 가능).
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
slots :
|
||||
- title : section.title
|
||||
- col_a_label : 좌 column header (예: "BIM")
|
||||
- col_b_label : 우 column header (예: "DX")
|
||||
- rows : list[{label, col_a, col_b}] — N category rows
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
4-class failure taxonomy :
|
||||
- class 1 adapter readiness : NEW builder `compare_table_2col` + NEW parser
|
||||
`compare_row_2col_item` 등록 필수 (PAYLOAD_BUILDERS / ITEM_PARSERS). 본 commit.
|
||||
- class 2 content-fit : row 수 max 12 (builder limit). cell content 한 줄 한계
|
||||
— 긴 문장 시 truncate 또는 wrap (CSS overflow-hidden).
|
||||
#}
|
||||
|
||||
<style>
|
||||
.f18b {
|
||||
width: 100%; height: 100%;
|
||||
display: flex; flex-direction: column;
|
||||
gap: 6px;
|
||||
font-family: 'Noto Sans KR', 'Pretendard', sans-serif;
|
||||
word-break: keep-all;
|
||||
}
|
||||
.f18b__title {
|
||||
font-size: var(--font-zone-title);
|
||||
font-weight: 700;
|
||||
line-height: var(--lh-zone-title);
|
||||
background-image: linear-gradient(180deg, #000 0%, #883700 100%);
|
||||
-webkit-background-clip: text; background-clip: text;
|
||||
color: transparent;
|
||||
flex-shrink: 0;
|
||||
filter: drop-shadow(0 0 3px rgba(50,44,30,0.4));
|
||||
}
|
||||
|
||||
/* compare table — 3-column (category / col_a / col_b) */
|
||||
.f18b__table {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 2fr 2fr;
|
||||
gap: 0;
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
border: 1px solid #A5BBB4;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
/* header row */
|
||||
.f18b__header {
|
||||
display: contents;
|
||||
}
|
||||
.f18b__header-cell {
|
||||
background: linear-gradient(180deg, rgba(50,31,9,0.85) 0%, rgba(50,31,9,0.95) 100%);
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
font-size: var(--font-caption);
|
||||
line-height: 1.2;
|
||||
padding: 6px 8px;
|
||||
text-align: center;
|
||||
border-bottom: 2px solid #A5BBB4;
|
||||
}
|
||||
.f18b__header-cell--category {
|
||||
background: linear-gradient(180deg, rgba(120,90,40,0.85) 0%, rgba(120,90,40,0.95) 100%);
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* data rows */
|
||||
.f18b__rows {
|
||||
display: contents;
|
||||
}
|
||||
.f18b__cell {
|
||||
padding: 5px 8px;
|
||||
font-size: var(--font-body);
|
||||
line-height: var(--lh-body);
|
||||
border-bottom: 1px solid rgba(165,187,180,0.4);
|
||||
color: #1a1a1a;
|
||||
overflow: hidden;
|
||||
}
|
||||
.f18b__cell--category {
|
||||
background: rgba(255,250,240,0.7);
|
||||
font-weight: 700;
|
||||
color: #5a4b2e; /* PROMOTED — brown family */
|
||||
text-align: center;
|
||||
}
|
||||
/* zebra striping (visual readability) — odd rows alternate */
|
||||
.f18b__row:nth-child(odd) .f18b__cell:not(.f18b__cell--category) {
|
||||
background: rgba(248,250,252,0.6);
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="f18b" data-frame-id="1171281195" data-template-id="bim_dx_comparison_table">
|
||||
<div class="f18b__title">{{ slot_payload.title }}</div>
|
||||
<div class="f18b__table">
|
||||
<div class="f18b__header">
|
||||
<div class="f18b__header-cell f18b__header-cell--category">구분</div>
|
||||
<div class="f18b__header-cell">{{ slot_payload.col_a_label | safe }}</div>
|
||||
<div class="f18b__header-cell">{{ slot_payload.col_b_label | safe }}</div>
|
||||
</div>
|
||||
<div class="f18b__rows">
|
||||
{% for row in slot_payload.rows %}
|
||||
<div class="f18b__row" style="display:contents;">
|
||||
<div class="f18b__cell f18b__cell--category">{{ row.label | safe }}</div>
|
||||
<div class="f18b__cell f18b__cell--col-a">{{ row.col_a | safe }}</div>
|
||||
<div class="f18b__cell f18b__cell--col-b">{{ row.col_b | safe }}</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,223 @@
|
||||
<!-- Phase Z-2 frame-derived adapted block.
|
||||
§17 룰 — Figma 시각 언어 promote, geometry 만 zone-compatible adapt. -->
|
||||
{#
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
Visual Provenance — figma_to_html_agent/blocks/1171281193/index.html
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
PROMOTED (Figma 1:1 변환물 → 그대로 사용):
|
||||
- card-bg gradient (TL/TR top→bottom) : line 49 → linear-gradient(180deg, #f2f2f2 0%, #ffffff 100%)
|
||||
- card-bg gradient (BL/BR bottom→top) : line 53-54 → linear-gradient(0deg, #f2f2f2 0%, #ffffff 100%)
|
||||
- header-ribbon (TL/BL — 갈색) : line 75, 79 → linear-gradient(270deg, rgba(165,161,150,0.5), #39321E 73%)
|
||||
- header-ribbon (TR/BR — 청록) : line 83, 87 → linear-gradient(90deg, rgba(41,107,85,0.5), #032118)
|
||||
- red headline color : line 127 → #ff0000
|
||||
- body-text color : line 136 → #000
|
||||
- center-quote (Rome wasn't Built in a day!) : line 233 (decorative, MDX 4-2.2 의 핵심 메시지로 대체 가능)
|
||||
- bullet marker : line 241 → "•"
|
||||
- card 모서리 radius : line 51-54 → 50px (top corners TL/TR, bottom corners BL/BR)
|
||||
|
||||
NOT PROMOTED (Figma 데코지만 MDX 04-2.2 에 없는 콘텐츠):
|
||||
- center-quote 의 영문 ("Rome wasn't Built in a day!") — slot_payload.center_quote 로 동적 (없으면 omit)
|
||||
|
||||
ADAPTED (Figma px / native size 무시, zone-compatible):
|
||||
- 2226×1766 inner + zoom 0.575 → CSS grid 2×2 (no zoom, no fixed inner)
|
||||
- Figma 60px ribbon font / 55px headline / 42px body → token-fixed (zone-title 13 / sub-title 12 / body 11)
|
||||
- 1080px card width / 119px ribbon height → grid 1fr 1fr / 22px ribbon
|
||||
- 644×584 center 원 → 90px 원 (zone-fit)
|
||||
- absolute positioning (4 quadrants) → grid-template-areas
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
slots: title, center_quote (옵션), quadrant_{1,2,3,4}_{label, body}
|
||||
- quadrant 1 = TL (정책 집행)
|
||||
- quadrant 2 = TR (수행 개념)
|
||||
- quadrant 3 = BL (근본 취지의 이해부족)
|
||||
- quadrant 4 = BR (지속적 투자 의지 부재)
|
||||
- body 형식 = text-line family 호환 HTML (text_lines list 또는 pre-rendered string)
|
||||
#}
|
||||
|
||||
<style>
|
||||
.f16b {
|
||||
width: 100%; height: 100%;
|
||||
display: flex; flex-direction: column;
|
||||
gap: 4px;
|
||||
font-family: 'Noto Sans KR', 'Pretendard', sans-serif;
|
||||
word-break: keep-all;
|
||||
position: relative;
|
||||
}
|
||||
.f16b__title {
|
||||
font-size: var(--font-zone-title);
|
||||
font-weight: 700;
|
||||
line-height: var(--lh-zone-title);
|
||||
color: #1e293b;
|
||||
flex-shrink: 0;
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
/* 4 quadrants — 2×2 grid (CSS grid-template-areas) */
|
||||
.f16b__quadrants {
|
||||
flex: 1;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-template-rows: 1fr 1fr;
|
||||
gap: 6px;
|
||||
position: relative;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.f16b__quadrant {
|
||||
display: flex; flex-direction: column;
|
||||
overflow: hidden;
|
||||
min-height: 0;
|
||||
padding: 0 8px 6px;
|
||||
/* PROMOTED — card-bg gradient */
|
||||
}
|
||||
.f16b__quadrant--tl {
|
||||
background: linear-gradient(180deg, #f2f2f2 0%, #ffffff 100%);
|
||||
border-radius: 14px 14px 0 0; /* PROMOTED 50px → adapted 14px */
|
||||
}
|
||||
.f16b__quadrant--tr {
|
||||
background: linear-gradient(180deg, #f2f2f2 0%, #ffffff 100%);
|
||||
border-radius: 14px 14px 0 0;
|
||||
}
|
||||
.f16b__quadrant--bl {
|
||||
background: linear-gradient(0deg, #f2f2f2 0%, #ffffff 100%);
|
||||
border-radius: 0 0 14px 14px;
|
||||
}
|
||||
.f16b__quadrant--br {
|
||||
background: linear-gradient(0deg, #f2f2f2 0%, #ffffff 100%);
|
||||
border-radius: 0 0 14px 14px;
|
||||
}
|
||||
|
||||
/* Header ribbon — PROMOTED gradient + token font */
|
||||
.f16b__ribbon {
|
||||
height: 22px;
|
||||
margin: 0 -4px 4px;
|
||||
border-radius: 999px;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
font-size: var(--font-sub-title);
|
||||
font-weight: 900;
|
||||
color: #fff;
|
||||
text-shadow: 0 0 3px #322c1e;
|
||||
flex-shrink: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
padding: 0 8px;
|
||||
}
|
||||
/* PROMOTED ribbon gradient — TL/BL 갈색, TR/BR 청록 (figma line 75,79,83,87) */
|
||||
.f16b__quadrant--tl .f16b__ribbon,
|
||||
.f16b__quadrant--bl .f16b__ribbon {
|
||||
background: linear-gradient(270deg, rgba(165,161,150,0.5) -26.87%, #39321E 73.13%);
|
||||
}
|
||||
.f16b__quadrant--tr .f16b__ribbon,
|
||||
.f16b__quadrant--br .f16b__ribbon {
|
||||
background: linear-gradient(90deg, rgba(41,107,85,0.5) 0%, #032118 100%);
|
||||
}
|
||||
|
||||
/* Body — red headline + text-line bullets */
|
||||
.f16b__body {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
min-height: 0;
|
||||
font-size: var(--font-body);
|
||||
line-height: var(--lh-body);
|
||||
color: #000;
|
||||
}
|
||||
.f16b__headline {
|
||||
color: #ff0000; /* PROMOTED line 127 */
|
||||
font-weight: 700;
|
||||
font-size: var(--font-sub-title);
|
||||
line-height: 1.3;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
/* text-line family 은 slide_base.html 의 공통 contract 사용 */
|
||||
|
||||
/* Center quote (옵션 — MDX 에 있을 때만) */
|
||||
.f16b__center {
|
||||
position: absolute;
|
||||
left: 50%; top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 80px; height: 80px;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(135deg, rgba(60,50,30,0.85), rgba(20,15,5,0.92));
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
z-index: 2;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.3);
|
||||
pointer-events: none;
|
||||
}
|
||||
.f16b__center-quote {
|
||||
color: #fff;
|
||||
font-size: 9px;
|
||||
font-weight: 700;
|
||||
text-align: center;
|
||||
line-height: 1.2;
|
||||
padding: 0 6px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="f16b" data-frame-id="1171281193" data-template-id="bim_issues_quadrant_four">
|
||||
{% if slot_payload.title %}
|
||||
<div class="f16b__title">{{ slot_payload.title }}</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="f16b__quadrants">
|
||||
|
||||
{# Quadrant 1 (TL) — 정책 집행 (갈색 ribbon) #}
|
||||
<div class="f16b__quadrant f16b__quadrant--tl">
|
||||
{% if slot_payload.quadrant_1_label %}
|
||||
<div class="f16b__ribbon">{{ slot_payload.quadrant_1_label | safe }}</div>
|
||||
{% endif %}
|
||||
{% if slot_payload.quadrant_1_headline or slot_payload.quadrant_1_body %}
|
||||
<div class="f16b__body">
|
||||
{% if slot_payload.quadrant_1_headline %}<div class="f16b__headline">{{ slot_payload.quadrant_1_headline | safe }}</div>{% endif %}
|
||||
{% for line in slot_payload.quadrant_1_body %}<div class="text-line text-line--bullet{% if line.indent > 0 %} text-line--indent-{{ line.indent }}{% endif %}">{{ line.text | safe }}</div>{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{# Quadrant 2 (TR) — 수행 개념 (청록 ribbon) #}
|
||||
<div class="f16b__quadrant f16b__quadrant--tr">
|
||||
{% if slot_payload.quadrant_2_label %}
|
||||
<div class="f16b__ribbon">{{ slot_payload.quadrant_2_label | safe }}</div>
|
||||
{% endif %}
|
||||
{% if slot_payload.quadrant_2_headline or slot_payload.quadrant_2_body %}
|
||||
<div class="f16b__body">
|
||||
{% if slot_payload.quadrant_2_headline %}<div class="f16b__headline">{{ slot_payload.quadrant_2_headline | safe }}</div>{% endif %}
|
||||
{% for line in slot_payload.quadrant_2_body %}<div class="text-line text-line--bullet{% if line.indent > 0 %} text-line--indent-{{ line.indent }}{% endif %}">{{ line.text | safe }}</div>{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{# Quadrant 3 (BL) — 근본 취지의 이해부족 (갈색 ribbon) #}
|
||||
<div class="f16b__quadrant f16b__quadrant--bl">
|
||||
{% if slot_payload.quadrant_3_label %}
|
||||
<div class="f16b__ribbon">{{ slot_payload.quadrant_3_label | safe }}</div>
|
||||
{% endif %}
|
||||
{% if slot_payload.quadrant_3_headline or slot_payload.quadrant_3_body %}
|
||||
<div class="f16b__body">
|
||||
{% if slot_payload.quadrant_3_headline %}<div class="f16b__headline">{{ slot_payload.quadrant_3_headline | safe }}</div>{% endif %}
|
||||
{% for line in slot_payload.quadrant_3_body %}<div class="text-line text-line--bullet{% if line.indent > 0 %} text-line--indent-{{ line.indent }}{% endif %}">{{ line.text | safe }}</div>{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{# Quadrant 4 (BR) — 지속적 투자 의지 부재 (청록 ribbon) #}
|
||||
<div class="f16b__quadrant f16b__quadrant--br">
|
||||
{% if slot_payload.quadrant_4_label %}
|
||||
<div class="f16b__ribbon">{{ slot_payload.quadrant_4_label | safe }}</div>
|
||||
{% endif %}
|
||||
{% if slot_payload.quadrant_4_headline or slot_payload.quadrant_4_body %}
|
||||
<div class="f16b__body">
|
||||
{% if slot_payload.quadrant_4_headline %}<div class="f16b__headline">{{ slot_payload.quadrant_4_headline | safe }}</div>{% endif %}
|
||||
{% for line in slot_payload.quadrant_4_body %}<div class="text-line text-line--bullet{% if line.indent > 0 %} text-line--indent-{{ line.indent }}{% endif %}">{{ line.text | safe }}</div>{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{# Center quote — 옵션 #}
|
||||
{% if slot_payload.center_quote %}
|
||||
<div class="f16b__center">
|
||||
<div class="f16b__center-quote">{{ slot_payload.center_quote | safe }}</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,169 @@
|
||||
<!-- Phase Z-2 MVP-1.5b frame-derived adapted block.
|
||||
§17 룰 — Figma 시각 언어 promote, geometry 만 zone-compatible adapt. -->
|
||||
{#
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
Visual Provenance — figma_to_html_agent/blocks/1171281182/ (frame 11)
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
Frame 11 = "시공단계 BIM 모델·정보 활용 구분" (cards-3-category, 1248×1066
|
||||
px, scale 0.67542). Figma 원본 = 3 horizontal stacked rows (각 row = brown
|
||||
label box at left + white content card at right with green border) + bottom
|
||||
BIM 모델/공사 Process 다이어그램 (deco).
|
||||
|
||||
본 partial = Track A frame 3 (Codex round 39 accepted, V4 strongest UAI tier).
|
||||
`index.html` base + Phase Z 규약 adapt + **compact MDX-mapped focus**.
|
||||
|
||||
3-layer architecture (matrix §0) :
|
||||
- V4 = matching authority — V4 ranked this frame as use_as_is for "01-1 용어 정의"
|
||||
(MDX 01) and restructure=1 다른 section. UAI tier post-F12.
|
||||
- figma_to_html = source/evidence — 401-line index.html + 4 PNG assets (title-icon,
|
||||
card_decor × 3). full A+T+I+F+S resource.
|
||||
- Phase Z = runtime orchestration — 본 commit 추가 runtime 자원 (catalog + partial + smoke).
|
||||
|
||||
PROMOTED — CSS (Figma 색/디자인 의도 → CSS 보존) :
|
||||
- 브라운 label box : rgba(50,31,9,0.8) bg + 우측 둥글기 (border-radius 0 20 20 0)
|
||||
+ drop-shadow — index.html L82-95
|
||||
- 라벨 typography : yellow (#FFE100) Korean + white English/subscript text — index.html L92-96
|
||||
- 화이트 content card : white bg + green border (#A5BBB4) — index.html L99-103
|
||||
- title gradient : F13/F14/F12 zone-title family (#000 ~ #883700)
|
||||
|
||||
NOT PROMOTED — Phase Z compact zone fit (자체 결정, P1 case-by-case, matrix §4.1 Fix 7) :
|
||||
- title-icon (50×50 PNG) — small icon, zone-size 에서 visible 효과 ↓
|
||||
- card_decor × 3 (260×120 decorative image at right side of each card) — Figma
|
||||
의 visual 풍부함이지만 MDX 내용과 무관 deco
|
||||
- 하단 BIM 모델/공사 Process 연계 다이어그램 — Figma 의 *대구도 시각* 으로
|
||||
compact zone (320px 정도) 에서 표현 불가. content 의 *bottom synthesis text* 가
|
||||
이 역할 대체 가능 — 단 현재 cardinality strict 3 (body) 라 별 slot 추가 X
|
||||
→ figma_to_html source evidence 는 *보존* (assets/ 폴더 그대로). 향후 *fidelity
|
||||
review* 시 promote 결정 가능 (preservation guardrail, Codex round 37 §3 정합).
|
||||
|
||||
ADAPTED :
|
||||
- Figma 50/45/38/30px → token-fixed (zone-title 13 / sub-title 12 / caption / body 11)
|
||||
- 1248×1066 absolute positioning + zoom 0.67542 → Phase Z flex column (3 row stack)
|
||||
- 335×124 label box → compact 90~110×40~50 box (zone fit)
|
||||
- 870×124 card → flex-1 (남은 width 차지)
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
min_height_px derivation (round 13 §2.2) :
|
||||
title 30 + 3 row × 70 (label + body 2-3 bullets) + gap 6×2 + padding 30 = 282
|
||||
+ safety buffer 38 = **320**. F29/F12 와 동등 class.
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
slots :
|
||||
- title : section.title
|
||||
- category_1_label / 2_label / 3_label : 3 category headings (quadrant_flat_slots)
|
||||
- category_1_body / 2_body / 3_body : 3 category bullet lists (text_lines)
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
4-class failure taxonomy (matrix §4.1 Fix 7) :
|
||||
- class 1 adapter readiness : `quadrant_flat_slots` builder 재사용 (pad_to=3 +
|
||||
key_pattern). 기존 F16 builder 미터치, secondary reuse 허용 (Codex round 39).
|
||||
- class 2 content-fit : 3 row stack + body bullets. row 별 ~70px 한계 →
|
||||
body 가 2-3 bullets 짧게. 4+ bullets 시 overflow watch.
|
||||
#}
|
||||
|
||||
<style>
|
||||
.f11b {
|
||||
width: 100%; height: 100%;
|
||||
display: flex; flex-direction: column;
|
||||
gap: 6px;
|
||||
font-family: 'Noto Sans KR', 'Pretendard', sans-serif;
|
||||
word-break: keep-all;
|
||||
}
|
||||
.f11b__title {
|
||||
font-size: var(--font-zone-title);
|
||||
font-weight: 700;
|
||||
line-height: var(--lh-zone-title);
|
||||
background-image: linear-gradient(180deg, #000 0%, #883700 100%);
|
||||
-webkit-background-clip: text; background-clip: text;
|
||||
color: transparent;
|
||||
flex-shrink: 0;
|
||||
filter: drop-shadow(0 0 3px rgba(50,44,30,0.4));
|
||||
}
|
||||
|
||||
/* 3 row stack — Figma 의 brown-label + white-card horizontal pair */
|
||||
.f11b__rows {
|
||||
display: flex; flex-direction: column;
|
||||
gap: 6px;
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
}
|
||||
.f11b__row {
|
||||
display: flex; align-items: stretch;
|
||||
gap: 0;
|
||||
flex: 1 1 0;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
/* label box — Figma L82-95 (rgba(50,31,9,0.8) brown + 둥글기 + drop-shadow) */
|
||||
.f11b__label {
|
||||
flex: 0 0 110px;
|
||||
background: rgba(50, 31, 9, 0.8);
|
||||
border-radius: 0 12px 12px 0;
|
||||
filter: drop-shadow(0 2px 1px rgba(0,0,0,0.25));
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
font-size: var(--font-sub-title);
|
||||
line-height: 1.15;
|
||||
letter-spacing: -0.04em;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
text-align: center;
|
||||
padding: 4px 6px;
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
/* white card — Figma L99-103 (white bg + green border #A5BBB4) */
|
||||
.f11b__card {
|
||||
flex: 1 1 auto;
|
||||
background: #fff;
|
||||
border: 2px solid #A5BBB4;
|
||||
border-radius: 12px;
|
||||
padding: 6px 10px;
|
||||
color: #1a1a1a;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
display: flex; flex-direction: column;
|
||||
gap: 2px;
|
||||
}
|
||||
.f11b__card .text-line {
|
||||
color: inherit;
|
||||
font-size: var(--font-body);
|
||||
line-height: var(--lh-body);
|
||||
position: relative;
|
||||
padding-left: 12px;
|
||||
}
|
||||
.f11b__card .text-line--bullet::before {
|
||||
content: "•";
|
||||
position: absolute;
|
||||
left: 2px; top: 0;
|
||||
color: #5a4b2e; /* PROMOTED — brown family */
|
||||
font-weight: 700;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="f11b" data-frame-id="1171281182" data-template-id="construction_bim_three_usage">
|
||||
<div class="f11b__title">{{ slot_payload.title }}</div>
|
||||
<div class="f11b__rows">
|
||||
{# 3 rows — quadrant_flat_slots produces category_N_label / category_N_body for N=1..3 #}
|
||||
<div class="f11b__row">
|
||||
<div class="f11b__label">{{ slot_payload.category_1_label | safe }}</div>
|
||||
<div class="f11b__card">
|
||||
{% if slot_payload.category_1_body %}
|
||||
{% for line in slot_payload.category_1_body %}<div class="text-line text-line--bullet{% if line.indent > 0 %} text-line--indent-{{ line.indent }}{% endif %}">{{ line.text | safe }}</div>{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="f11b__row">
|
||||
<div class="f11b__label">{{ slot_payload.category_2_label | safe }}</div>
|
||||
<div class="f11b__card">
|
||||
{% if slot_payload.category_2_body %}
|
||||
{% for line in slot_payload.category_2_body %}<div class="text-line text-line--bullet{% if line.indent > 0 %} text-line--indent-{{ line.indent }}{% endif %}">{{ line.text | safe }}</div>{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="f11b__row">
|
||||
<div class="f11b__label">{{ slot_payload.category_3_label | safe }}</div>
|
||||
<div class="f11b__card">
|
||||
{% if slot_payload.category_3_body %}
|
||||
{% for line in slot_payload.category_3_body %}<div class="text-line text-line--bullet{% if line.indent > 0 %} text-line--indent-{{ line.indent }}{% endif %}">{{ line.text | safe }}</div>{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
<!-- Phase Z-2 MVP-1.5b frame-derived adapted block.
|
||||
§17 룰 — Figma 시각 언어 promote, geometry 만 zone-compatible adapt. -->
|
||||
{#
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
Visual Provenance — figma_to_html_agent/blocks/1171281189/ (frame 12)
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
Frame 12 = "건설산업의 목표 (BIM 의 목적)" (cycle-3way-intersection, 2195×1195
|
||||
px, scale 0.58312). Figma 원본 = 3 메인 원 (안전·품질 / 생산성·향상 / 소통·
|
||||
신뢰) + 6 액센트 한자 원 (安/質/速/利/通/信) + 6 사이드 라벨 (안전성 제고 등)
|
||||
+ 3 장식 rect + 3 arc + bg texture.
|
||||
|
||||
본 partial = Track A frame 2 (Codex round 30/33/35 합의, V4 strongest UAI tier).
|
||||
`index.html` (510 lines) base + Phase Z 규약 adapt + **compact MDX-mapped focus**
|
||||
(MDX 콘텐츠와 직접 매핑되는 5 slots 만 유지. Figma 의 frame-side decoration
|
||||
는 NOT PROMOTED — zone 사이즈에서 cluttered 회피).
|
||||
|
||||
PROMOTED — CSS (Figma 색/디자인 의도 → CSS 으로 충분) :
|
||||
- circle 1 (safety) gradient : index.html L142-145 (outer) + L149-154 (inner)
|
||||
outer = linear-gradient(145.28deg, #FDC69E, #E0782C) multiply blend
|
||||
inner = linear-gradient(145.28deg, #BC652B, #A24200) + white border + shadow
|
||||
- circle 2 (productivity) : index.html L158-172
|
||||
outer = linear-gradient(218.84deg, #D5AA89, #737373) multiply
|
||||
inner = linear-gradient(153.95deg, #897445, #3E3523) + white border
|
||||
- circle 3 (trust) : index.html L175-189
|
||||
outer = linear-gradient(145.90deg, #FFFFFF, #253E1F) multiply
|
||||
inner = linear-gradient(153.95deg, #296B55, #123328) + white border
|
||||
- title gradient : #000 → #883700 (index.html L42-46) — F13/F14 zone-title 와 동일 family
|
||||
- main label typography : 700 weight, white, text-shadow (index.html L192-204)
|
||||
|
||||
NOT PROMOTED — Phase Z compact zone fit (자체 결정, P1 case-by-case) :
|
||||
- 6 액센트 한자 원 (安/質/速/利/通/信) — Figma 외 deco, MDX 무관, zone 사이즈에서 cluttered
|
||||
- 6 사이드 라벨 (안전성 제고 / 품질 향상 / 신속·정확성 증진 / 비용저감 / 소통·이해 / 신뢰·투명성)
|
||||
— Figma source 의 정해진 문구. MDX content 와 무관 deco text
|
||||
- 3 장식 rect (gradient 곡선 wrap) + 3 arc 이미지 — Figma 의 시각 풍부함이지만 zone-size 에서 visible 효과 약함
|
||||
- bg-texture multiply image (index.html L375) — zone 사이즈에서 effect 미미
|
||||
|
||||
ADAPTED :
|
||||
- Figma 70/50/40px → token-fixed (zone-title 13 / sub-title 12 / caption / body 11)
|
||||
- 3 메인 원 absolute positioning + zoom 0.58312 → Phase Z flex/grid (3-circle row)
|
||||
- 350×350 원 사이즈 → compact 70-90 px circle (zone fit)
|
||||
- Figma 의 3 원 *겹침 layout* (안전-품질 위 / 생산성 좌 / 소통 우) → flex row (분리, *cycle 의 의미*는 intersection text 가 표현)
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
min_height_px derivation (Codex round 13 §2.2 — derive + confirm) :
|
||||
Figma frame 1195 px @ scale 0.58312 → 697 px adapted (full frame, 6 deco 포함).
|
||||
Phase Z compact (3 메인 원 + title + intersection) :
|
||||
title 30 + 3 circle row 80 + label area 60 + intersection 30 + padding 40 = 240 px
|
||||
+ safety buffer (가벼운 텍스트 overflow 보호) 80 = **320** (F14 350 보다 가벼움).
|
||||
Confirm via smoke harness `--render-to` artifact.
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
slots :
|
||||
- title : section.title (Jinja 변수)
|
||||
- circle_1_label / 2_label / 3_label : 3 메인 원 label (cycle_intersect_3 builder 산출)
|
||||
- intersection : 중앙 교차 텍스트 (optional)
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
4-class failure taxonomy (matrix §4.1 Fix 7) :
|
||||
- class 1 adapter readiness 보호 : new builder cycle_intersect_3 가 PAYLOAD_BUILDERS
|
||||
에 등록되어야 contract 가 valid. 안 등록 시 → builder None → 본 frame runtime fail
|
||||
- class 2 content-fit : MDX 의 3 bullets 가 너무 길면 (label > ~20 chars) overflow.
|
||||
label 짧게 (compact) 권장
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
#}
|
||||
|
||||
<style>
|
||||
.f12b {
|
||||
width: 100%; height: 100%;
|
||||
display: flex; flex-direction: column;
|
||||
gap: 6px;
|
||||
font-family: 'Noto Sans KR', 'Pretendard', sans-serif;
|
||||
word-break: keep-all;
|
||||
}
|
||||
.f12b__title {
|
||||
font-size: var(--font-zone-title);
|
||||
font-weight: 700;
|
||||
line-height: var(--lh-zone-title);
|
||||
background-image: linear-gradient(180deg, #000 0%, #883700 100%);
|
||||
-webkit-background-clip: text; background-clip: text;
|
||||
color: transparent;
|
||||
flex-shrink: 0;
|
||||
filter: drop-shadow(0 0 3px rgba(50,44,30,0.4));
|
||||
}
|
||||
|
||||
/* 3 circle row — compact flex layout (Figma 의 겹침 cycle layout 단순화) */
|
||||
.f12b__circles {
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
gap: 16px;
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
padding: 8px 0;
|
||||
}
|
||||
.f12b__circle {
|
||||
flex: 0 0 auto;
|
||||
width: 110px; height: 110px;
|
||||
border-radius: 50%;
|
||||
position: relative;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
box-shadow: 0 0 10px rgba(0,0,0,0.3);
|
||||
}
|
||||
/* outer ring (Figma multiply blend 의도) — CSS gradient approximation */
|
||||
.f12b__circle::before {
|
||||
content: "";
|
||||
position: absolute; inset: -8px;
|
||||
border-radius: 50%;
|
||||
z-index: -1;
|
||||
mix-blend-mode: multiply;
|
||||
}
|
||||
/* per-circle gradient (PROMOTED from index.html L141-189) */
|
||||
.f12b__circle--safety {
|
||||
background: linear-gradient(145.28deg, #BC652B 16.04%, #A24200 55.20%);
|
||||
border: 3px solid #fff;
|
||||
}
|
||||
.f12b__circle--safety::before {
|
||||
background: linear-gradient(145.28deg, #FDC69E 16.04%, #E0782C 55.20%);
|
||||
}
|
||||
.f12b__circle--productivity {
|
||||
background: linear-gradient(153.95deg, #897445 15.27%, #3E3523 61.74%);
|
||||
border: 3px solid #fff;
|
||||
}
|
||||
.f12b__circle--productivity::before {
|
||||
background: linear-gradient(218.84deg, #D5AA89 14.08%, #737373 92.67%);
|
||||
}
|
||||
.f12b__circle--trust {
|
||||
background: linear-gradient(153.95deg, #296B55 15.27%, #123328 61.74%);
|
||||
border: 3px solid #fff;
|
||||
}
|
||||
.f12b__circle--trust::before {
|
||||
background: linear-gradient(145.90deg, #FFFFFF 8.47%, #253E1F 87.56%);
|
||||
}
|
||||
|
||||
/* circle 안 label (white text + shadow, index.html L192-204) */
|
||||
.f12b__circle-label {
|
||||
color: #fff;
|
||||
font-size: var(--font-caption);
|
||||
font-weight: 700;
|
||||
line-height: 1.1;
|
||||
text-align: center;
|
||||
padding: 4px;
|
||||
text-shadow: 0 0 4px rgba(0,0,0,0.6);
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
/* intersection — 중앙 교차 텍스트 (optional, MDX 의 emphasis content) */
|
||||
.f12b__intersection {
|
||||
flex-shrink: 0;
|
||||
text-align: center;
|
||||
padding: 6px 12px;
|
||||
font-size: var(--font-sub-title);
|
||||
font-weight: 700;
|
||||
color: #883700; /* PROMOTED — title gradient 의 end color */
|
||||
background: linear-gradient(180deg, rgba(255,250,240,0.6) 0%, rgba(255,250,240,0) 100%);
|
||||
border-top: 1px dashed #883700;
|
||||
line-height: 1.3;
|
||||
min-height: 0;
|
||||
}
|
||||
.f12b__intersection:empty {
|
||||
display: none; /* slot 빈 경우 자동 hide */
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="f12b" data-frame-id="1171281189" data-template-id="construction_goals_three_circle_intersection">
|
||||
<div class="f12b__title">{{ slot_payload.title }}</div>
|
||||
<div class="f12b__circles">
|
||||
<div class="f12b__circle f12b__circle--safety">
|
||||
<div class="f12b__circle-label">{{ slot_payload.circle_1_label | safe }}</div>
|
||||
</div>
|
||||
<div class="f12b__circle f12b__circle--productivity">
|
||||
<div class="f12b__circle-label">{{ slot_payload.circle_2_label | safe }}</div>
|
||||
</div>
|
||||
<div class="f12b__circle f12b__circle--trust">
|
||||
<div class="f12b__circle-label">{{ slot_payload.circle_3_label | safe }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="f12b__intersection">{{ slot_payload.intersection | safe }}</div>
|
||||
</div>
|
||||
@@ -0,0 +1,158 @@
|
||||
<!-- Phase Z-2 MVP-1.5b frame-derived adapted block.
|
||||
§17 룰 — Figma 시각 언어 promote, geometry 만 zone-compatible adapt. -->
|
||||
{#
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
Visual Provenance — figma_to_html_agent/blocks/1171281198/ (frame 20)
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
Frame 20 = "디지털 전환(DX)은 S/W가 필수다" (cards-3-header). Figma 원본 =
|
||||
상단 dark green banner ("디지털 전환(DX)은 S/W가 필수다" green/white mix) +
|
||||
좌측 DX circular area + 우측 3 perspective cards (BIM 전면설계 / 디지털
|
||||
전환 S/W / 고부가가치 산업전환).
|
||||
|
||||
본 partial = Track A frame 5 (Codex round 45 accepted, V4 LE tier strongest).
|
||||
builder 재사용 = `quadrant_flat_slots` (F11 cards-3-category pattern). 새
|
||||
builder/parser 0.
|
||||
|
||||
3-layer architecture (matrix §0) :
|
||||
- V4 = matching authority — V4 ranked this frame light_edit for 03-1 + 01-1.
|
||||
- figma_to_html (1171281198) = source/evidence — 386-line index.html + assets/.
|
||||
- Phase Z = runtime — 본 commit adds catalog + partial + smoke fixture.
|
||||
|
||||
PROMOTED — CSS :
|
||||
- 3 column header bg : dark green (`#296B55` family, Figma green theme)
|
||||
- header text white bold + green accent
|
||||
- title gradient (#000 → #883700, F13/F14/F12/F11/F18 zone-title family)
|
||||
- card border + bullet markers (green family)
|
||||
|
||||
NOT PROMOTED (P1 case-by-case, compact zone fit) :
|
||||
- 상단 dark green banner (Figma 의 큰 visual 영역, MDX 의 *title 만* 핵심)
|
||||
- 좌측 DX circular area (multi-image + center text + decor — Figma 의 main
|
||||
rhetorical anchor 단 compact zone 에서 표현 불가). title 의 gradient 로 의도 보존
|
||||
- 한자/장식/배경 텍스처 — Figma source evidence 보존, 미 promote
|
||||
|
||||
ADAPTED :
|
||||
- Figma 90/65/40px → token-fixed (zone-title 13 / sub-title 12 / caption / body 11)
|
||||
- 1280×426 absolute positioning + zoom → Phase Z 3-column grid
|
||||
- 3 perspective cards (header + body) → flex column
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
min_height_px derivation :
|
||||
3 col × (header 30 + body 3-bullets × 25) + title 30 + padding 30 = ~195
|
||||
+ safety buffer (longer label / 5+ bullets) 125 = **320**. F12/F11/F18 class.
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
slots :
|
||||
- title : section.title
|
||||
- perspective_1/2/3_label : 3 column headers
|
||||
- perspective_1/2/3_body : list[{text, indent}] : 3 column bullets
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
4-class failure taxonomy :
|
||||
- class 1 readiness : builder reuse `quadrant_flat_slots` + `quadrant_item`.
|
||||
contract + partial + smoke fixture.
|
||||
- class 2 content-fit : header label 짧게 (single line). body 3-5 bullets per
|
||||
column (zone fit). 6+ bullets 시 watch.
|
||||
#}
|
||||
|
||||
<style>
|
||||
.f20b {
|
||||
width: 100%; height: 100%;
|
||||
display: flex; flex-direction: column;
|
||||
gap: 6px;
|
||||
font-family: 'Noto Sans KR', 'Pretendard', sans-serif;
|
||||
word-break: keep-all;
|
||||
}
|
||||
.f20b__title {
|
||||
font-size: var(--font-zone-title);
|
||||
font-weight: 700;
|
||||
line-height: var(--lh-zone-title);
|
||||
background-image: linear-gradient(180deg, #000 0%, #883700 100%);
|
||||
-webkit-background-clip: text; background-clip: text;
|
||||
color: transparent;
|
||||
flex-shrink: 0;
|
||||
filter: drop-shadow(0 0 3px rgba(50,44,30,0.4));
|
||||
}
|
||||
|
||||
/* 3-column grid — Figma cards-3-header pattern */
|
||||
.f20b__cols {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
gap: 10px;
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
}
|
||||
.f20b__col {
|
||||
display: flex; flex-direction: column;
|
||||
border: 2px solid #296B55; /* PROMOTED — green family from Figma */
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
background: #fff;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
/* header bar (top of each card, dark green per Figma) */
|
||||
.f20b__header {
|
||||
background: linear-gradient(180deg, #296B55 0%, #123328 100%); /* PROMOTED — Figma green theme */
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
font-size: var(--font-sub-title);
|
||||
line-height: 1.15;
|
||||
padding: 6px 10px;
|
||||
text-align: center;
|
||||
flex-shrink: 0;
|
||||
letter-spacing: -0.04em;
|
||||
}
|
||||
|
||||
/* body — bullet list (CSS check marker, F14 pattern) */
|
||||
.f20b__body {
|
||||
flex: 1 1 auto;
|
||||
overflow: hidden;
|
||||
padding: 6px 10px 8px;
|
||||
color: #1a1a1a;
|
||||
min-height: 0;
|
||||
display: flex; flex-direction: column;
|
||||
gap: 3px;
|
||||
}
|
||||
.f20b__body .text-line {
|
||||
color: inherit;
|
||||
font-size: var(--font-body);
|
||||
line-height: var(--lh-body);
|
||||
position: relative;
|
||||
padding-left: 14px;
|
||||
}
|
||||
.f20b__body .text-line--bullet::before {
|
||||
content: "\2713"; /* ✓ check mark — green theme */
|
||||
position: absolute;
|
||||
left: 0; top: 0;
|
||||
color: #296B55; /* PROMOTED — green family */
|
||||
font-weight: 700;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="f20b" data-frame-id="1171281198" data-template-id="dx_sw_necessity_three_perspectives">
|
||||
<div class="f20b__title">{{ slot_payload.title }}</div>
|
||||
<div class="f20b__cols">
|
||||
{# 3 columns — quadrant_flat_slots produces perspective_N_label / perspective_N_body for N=1..3 #}
|
||||
<div class="f20b__col">
|
||||
<div class="f20b__header">{{ slot_payload.perspective_1_label | safe }}</div>
|
||||
<div class="f20b__body">
|
||||
{% if slot_payload.perspective_1_body %}
|
||||
{% for line in slot_payload.perspective_1_body %}<div class="text-line text-line--bullet{% if line.indent > 0 %} text-line--indent-{{ line.indent }}{% endif %}">{{ line.text | safe }}</div>{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="f20b__col">
|
||||
<div class="f20b__header">{{ slot_payload.perspective_2_label | safe }}</div>
|
||||
<div class="f20b__body">
|
||||
{% if slot_payload.perspective_2_body %}
|
||||
{% for line in slot_payload.perspective_2_body %}<div class="text-line text-line--bullet{% if line.indent > 0 %} text-line--indent-{{ line.indent }}{% endif %}">{{ line.text | safe }}</div>{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="f20b__col">
|
||||
<div class="f20b__header">{{ slot_payload.perspective_3_label | safe }}</div>
|
||||
<div class="f20b__body">
|
||||
{% if slot_payload.perspective_3_body %}
|
||||
{% for line in slot_payload.perspective_3_body %}<div class="text-line text-line--bullet{% if line.indent > 0 %} text-line--indent-{{ line.indent }}{% endif %}">{{ line.text | safe }}</div>{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,152 @@
|
||||
<!-- Phase Z-2 MVP-1.5b frame-derived adapted block.
|
||||
§17 룰 — Figma 시각 언어 promote, geometry 만 zone-compatible adapt. -->
|
||||
{#
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
Visual Provenance — figma_to_html_agent/blocks/1171281179/ (frame 8)
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
Frame 8 = "효율적인 정보의 관리와 활용 (What/How/When)" (cards/3-section-framework).
|
||||
3 sections framework — What (무슨 정보) / How (어떻게 연계) / When (언제 사용).
|
||||
정보 관리·활용 3관점 병렬 제시 디자인.
|
||||
|
||||
본 partial = Track A frame 6 (Codex round 47 V4-zero catalog-completeness
|
||||
activation guardrail). **V4 신호 0** (4 MDX sample 기준). 32-frame all-in
|
||||
scope 채우는 등록 — V4 가 다른 MDX 에서 본 frame 을 추천 시 backend 받음.
|
||||
*V4 endorsement 아님* — V4 = matching authority 보존, Phase Z 는 runtime
|
||||
availability 추가만.
|
||||
|
||||
3-layer architecture (matrix §0) :
|
||||
- V4 = matching authority — 본 frame 은 4 MDX 에서 미선택 (UAI/LE/RS = 0).
|
||||
단 V4 evidence 미 cover 의 MDX 가 추천 시 backend 가 받을 수 있게 등록.
|
||||
- figma_to_html (1171281179) = source/evidence — analysis + texts + index +
|
||||
flat + assets 모두 보유. 본 partial 의 visual base.
|
||||
- Phase Z = runtime — catalog + partial + smoke fixture 추가.
|
||||
|
||||
PROMOTED — CSS :
|
||||
- 3 section header color (W/H/W = What/How/When framework)
|
||||
- title gradient (zone-title family — F13/F14/F12/F11/F18/F20/F8 등 동일)
|
||||
- card border + bullet markers
|
||||
|
||||
NOT PROMOTED (P1 case-by-case + preservation guardrail) :
|
||||
- Figma 의 상단 banner / icon / 배경 텍스처 / 장식 image 등 — figma_to_html
|
||||
source evidence 보존, compact zone fit 위해 미 promote
|
||||
|
||||
ADAPTED :
|
||||
- Figma 50px+ → token-fixed
|
||||
- absolute positioning → Phase Z 3-column grid
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
min_height_px = 320 (F11/F20 와 동등 — 3-column header + body)
|
||||
slots : title, section_1/2/3_label, section_1/2/3_body
|
||||
4-class status :
|
||||
- class 1 ready (builder reuse + partial + smoke)
|
||||
- class 2 watch (body 5+ bullets per column)
|
||||
#}
|
||||
|
||||
<style>
|
||||
.f8b {
|
||||
width: 100%; height: 100%;
|
||||
display: flex; flex-direction: column;
|
||||
gap: 6px;
|
||||
font-family: 'Noto Sans KR', 'Pretendard', sans-serif;
|
||||
word-break: keep-all;
|
||||
}
|
||||
.f8b__title {
|
||||
font-size: var(--font-zone-title);
|
||||
font-weight: 700;
|
||||
line-height: var(--lh-zone-title);
|
||||
background-image: linear-gradient(180deg, #000 0%, #883700 100%);
|
||||
-webkit-background-clip: text; background-clip: text;
|
||||
color: transparent;
|
||||
flex-shrink: 0;
|
||||
filter: drop-shadow(0 0 3px rgba(50,44,30,0.4));
|
||||
}
|
||||
|
||||
.f8b__cols {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
gap: 10px;
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
}
|
||||
.f8b__col {
|
||||
display: flex; flex-direction: column;
|
||||
border: 2px solid;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
background: #fff;
|
||||
min-height: 0;
|
||||
}
|
||||
/* per-section accent — W/H/W theme (다른 frame 들과 차별) */
|
||||
.f8b__col:nth-child(1) { border-color: #2563eb; } /* What — blue */
|
||||
.f8b__col:nth-child(2) { border-color: #ea580c; } /* How — orange */
|
||||
.f8b__col:nth-child(3) { border-color: #16a34a; } /* When — green */
|
||||
|
||||
.f8b__header {
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
font-size: var(--font-sub-title);
|
||||
line-height: 1.15;
|
||||
padding: 6px 10px;
|
||||
text-align: center;
|
||||
flex-shrink: 0;
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
.f8b__col:nth-child(1) .f8b__header { background: linear-gradient(180deg, #2563eb 0%, #1e40af 100%); }
|
||||
.f8b__col:nth-child(2) .f8b__header { background: linear-gradient(180deg, #ea580c 0%, #c2410c 100%); }
|
||||
.f8b__col:nth-child(3) .f8b__header { background: linear-gradient(180deg, #16a34a 0%, #15803d 100%); }
|
||||
|
||||
.f8b__body {
|
||||
flex: 1 1 auto;
|
||||
overflow: hidden;
|
||||
padding: 6px 10px 8px;
|
||||
color: #1a1a1a;
|
||||
min-height: 0;
|
||||
display: flex; flex-direction: column;
|
||||
gap: 3px;
|
||||
}
|
||||
.f8b__body .text-line {
|
||||
color: inherit;
|
||||
font-size: var(--font-body);
|
||||
line-height: var(--lh-body);
|
||||
position: relative;
|
||||
padding-left: 14px;
|
||||
}
|
||||
.f8b__body .text-line--bullet::before {
|
||||
content: "•";
|
||||
position: absolute;
|
||||
left: 2px; top: 0;
|
||||
font-weight: 700;
|
||||
}
|
||||
.f8b__col:nth-child(1) .f8b__body .text-line--bullet::before { color: #2563eb; }
|
||||
.f8b__col:nth-child(2) .f8b__body .text-line--bullet::before { color: #ea580c; }
|
||||
.f8b__col:nth-child(3) .f8b__body .text-line--bullet::before { color: #16a34a; }
|
||||
</style>
|
||||
|
||||
<div class="f8b" data-frame-id="1171281179" data-template-id="info_management_what_how_when">
|
||||
<div class="f8b__title">{{ slot_payload.title }}</div>
|
||||
<div class="f8b__cols">
|
||||
<div class="f8b__col">
|
||||
<div class="f8b__header">{{ slot_payload.section_1_label | safe }}</div>
|
||||
<div class="f8b__body">
|
||||
{% if slot_payload.section_1_body %}
|
||||
{% for line in slot_payload.section_1_body %}<div class="text-line text-line--bullet{% if line.indent > 0 %} text-line--indent-{{ line.indent }}{% endif %}">{{ line.text | safe }}</div>{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="f8b__col">
|
||||
<div class="f8b__header">{{ slot_payload.section_2_label | safe }}</div>
|
||||
<div class="f8b__body">
|
||||
{% if slot_payload.section_2_body %}
|
||||
{% for line in slot_payload.section_2_body %}<div class="text-line text-line--bullet{% if line.indent > 0 %} text-line--indent-{{ line.indent }}{% endif %}">{{ line.text | safe }}</div>{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="f8b__col">
|
||||
<div class="f8b__header">{{ slot_payload.section_3_label | safe }}</div>
|
||||
<div class="f8b__body">
|
||||
{% if slot_payload.section_3_body %}
|
||||
{% for line in slot_payload.section_3_body %}<div class="text-line text-line--bullet{% if line.indent > 0 %} text-line--indent-{{ line.indent }}{% endif %}">{{ line.text | safe }}</div>{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,294 @@
|
||||
<!-- Phase Z-2 MVP-1.5b frame-derived adapted block.
|
||||
§17 룰 — Figma 시각 언어 promote, geometry 만 zone-compatible adapt. -->
|
||||
{#
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
Visual Provenance — figma_to_html_agent/blocks/1171281210/index.html
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
PROMOTED (Figma 1:1 변환물 → 그대로 사용):
|
||||
- banner-left text gradient : lines 101-104 → linear-gradient(90deg, rgb(62,53,35), rgb(62,53,35)) on linear-gradient(180deg, rgb(41,107,85), rgb(18,51,40))
|
||||
- banner-right text gradient : lines 110-113 → linear-gradient(90deg, rgb(34,95,74), rgb(34,95,74)) on linear-gradient(180deg, rgb(41,107,85), rgb(18,51,40))
|
||||
- banner-left bg gradient : lines 84-91 → linear-gradient(to right, rgba(136,131,118,.343), #39321E 73.1%, #39321E) + border-radius pill
|
||||
- banner-right bg gradient : lines 92-98 → linear-gradient(to right, #032118, rgba(41,107,85,.1)) + border-radius pill
|
||||
- body bg gradients (좌/우) : lines 53-68 → multi-bg / 좌(57,50,30) α0.3 → white α0.3, 우(41,107,85) α0.3 → white α0.3
|
||||
- section-title-left color : line 125 → #5C3714 (갈)
|
||||
- section-title-right color : line 126 → #084C56 (짙은 청록)
|
||||
- bullets text : line 136 → 700 / #000 / list-disc
|
||||
- arrow PNG asset : line 220 → assets/arrow.png (AS-IS → TO-BE)
|
||||
- footnote (*) inline : lines 144, 281-283 → 25.8px small + indent
|
||||
|
||||
(2026-05-08 수정) 원본 SVG 3 개 (header_left_bg / header_right_bg / body_bg) → CSS gradient 로 재현.
|
||||
asset 파일 부재 (figma 원본 R8 룰 = "순수 CSS 우선" 따라 SVG 자체 미생성). 시각 fidelity 동일.
|
||||
|
||||
ADAPTED (Figma px / native 무시, zone flex 재구성):
|
||||
- 3848×1388 inner + zoom 0.33270 → flex layout (no zoom, no fixed inner)
|
||||
- 70px banner / 50px section / 40px body→ var(--font-sub-title) / 8-10px / var(--font-caption)
|
||||
- absolute left/top px → flex grid (no absolute)
|
||||
- banner heights 142px + body 933px → 비율 기반 flex (banner ~28%, body ~72%)
|
||||
- assets 1921×142 / 3845×933 sizes → object-fit cover, 비율 유지
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
slots: title (omitted), banner_left, banner_right,
|
||||
process.sections[3] (s[0]: AS-IS/TO-BE, s[1-2]: bullets),
|
||||
product.sections[3] (bullets, optional footnote/sub_title)
|
||||
#}
|
||||
|
||||
<style>
|
||||
.f29b {
|
||||
width: 100%; height: 100%;
|
||||
display: flex; flex-direction: column;
|
||||
gap: 4px;
|
||||
position: relative;
|
||||
font-family: 'Noto Sans KR', 'Pretendard', sans-serif;
|
||||
word-break: keep-all;
|
||||
overflow: hidden;
|
||||
}
|
||||
.f29b__title {
|
||||
font-size: var(--font-zone-title); /* 13px — frame 13 의 f13b__title 과 동일 위계 */
|
||||
font-weight: 700;
|
||||
line-height: var(--lh-zone-title);
|
||||
background-image: linear-gradient(180deg, #000 0%, #883700 100%);
|
||||
-webkit-background-clip: text; background-clip: text;
|
||||
color: transparent;
|
||||
flex-shrink: 0;
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
/* banners — top */
|
||||
.f29b__banners {
|
||||
flex: 0 0 auto;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 4px;
|
||||
position: relative;
|
||||
height: 36px;
|
||||
}
|
||||
.f29b__banner {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
}
|
||||
/* PROMOTED background gradients — figma origin lines 84-98 (header-bg--left/right).
|
||||
원본 SVG 3 개 → CSS gradient 로 재현 (R8/R9 준수). border-radius 9999px = 자동 pill. */
|
||||
.f29b__banner--left {
|
||||
background: linear-gradient(to right,
|
||||
rgba(136, 131, 118, 0.343) 0%,
|
||||
#39321E 73.1%,
|
||||
#39321E 100%);
|
||||
border-radius: 0 9999px 9999px 0;
|
||||
}
|
||||
.f29b__banner--right {
|
||||
background: linear-gradient(to right,
|
||||
#032118 0%,
|
||||
rgba(41, 107, 85, 0.1) 100%);
|
||||
border-radius: 9999px 0 0 9999px;
|
||||
}
|
||||
.f29b__banner-text {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
font-size: var(--font-sub-title);
|
||||
font-weight: 900;
|
||||
line-height: 1;
|
||||
text-shadow: 0 0 2px #322C1E;
|
||||
-webkit-background-clip: text; background-clip: text;
|
||||
color: transparent;
|
||||
padding: 0 8px;
|
||||
}
|
||||
/* PROMOTED gradient — lines 101-104 / 110-113 */
|
||||
.f29b__banner--left .f29b__banner-text {
|
||||
background-image:
|
||||
linear-gradient(90deg, rgb(62,53,35) 0%, rgb(62,53,35) 100%),
|
||||
linear-gradient(180deg, rgb(41,107,85) 0%, rgb(18,51,40) 100%);
|
||||
}
|
||||
.f29b__banner--right .f29b__banner-text {
|
||||
background-image:
|
||||
linear-gradient(90deg, rgb(34,95,74) 0%, rgb(34,95,74) 100%),
|
||||
linear-gradient(180deg, rgb(41,107,85) 0%, rgb(18,51,40) 100%);
|
||||
}
|
||||
|
||||
/* body — 6 cell grid (3 rows × 2 cols) — 좌우 row divider Y 정렬 */
|
||||
/* PROMOTED background — figma origin lines 53-68 (body-bg-left/right).
|
||||
좌(0~50%): #39321E α0.3 (top) → white α0.3 (bottom)
|
||||
우(50~100%): #296B55 α0.3 (top) → white α0.3 (bottom)
|
||||
원본 SVG → CSS multi-bg 로 재현. */
|
||||
.f29b__body {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
min-height: 0;
|
||||
padding-top: 4px;
|
||||
background:
|
||||
linear-gradient(to bottom, rgba(57,50,30,0.3) 0%, rgba(255,255,255,0.3) 100%) 0% 0% / 50% 100% no-repeat,
|
||||
linear-gradient(to bottom, rgba(41,107,85,0.3) 0%, rgba(255,255,255,0.3) 100%) 100% 0% / 50% 100% no-repeat;
|
||||
}
|
||||
|
||||
/* 6 cell grid: 3 rows (section 1/2/3), 2 cols (process/product). 각 row 의 height = max(좌, 우) */
|
||||
.f29b__grid {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-auto-rows: auto;
|
||||
gap: 6px 10px;
|
||||
padding: 4px 8px;
|
||||
height: 100%;
|
||||
align-content: start;
|
||||
}
|
||||
.f29b__cell {
|
||||
overflow: hidden;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
}
|
||||
/* row 2/3 (3 번째 cell 이후) 위에 dashed divider — 좌우 같은 Y */
|
||||
.f29b__cell:nth-child(n+3) {
|
||||
border-top: 1px dashed rgba(0,0,0,0.15);
|
||||
padding-top: 6px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
/* section-title — 부소목차 (사용자 5-layer 직설 2026-05-07): Analogue 기반... 같은 깊이 0 굵은 bullet */
|
||||
.f29b__section-title {
|
||||
font-size: var(--font-sub-title); /* 12px — 부소목차 위계 */
|
||||
font-weight: 900;
|
||||
line-height: 1.3;
|
||||
margin-bottom: 5px;
|
||||
padding-left: 6px;
|
||||
border-left: 3px solid currentColor;
|
||||
}
|
||||
.f29b__cell--left .f29b__section-title { color: #5C3714; } /* PROMOTED line 125 */
|
||||
.f29b__cell--right .f29b__section-title { color: #084C56; } /* PROMOTED line 126 */
|
||||
.f29b__section-title__sub {
|
||||
font-size: var(--font-caption); /* 10px */
|
||||
margin-left: 3px;
|
||||
}
|
||||
/* f29b 의 본문 = .text-line 공통 contract 사용. bullet color override. */
|
||||
.f29b__cell .text-line--bullet { color: #000; font-weight: 700; }
|
||||
|
||||
/* AS-IS/TO-BE 좌우 + arrow (PROMOTED 구조) */
|
||||
.f29b__transform {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto 1fr;
|
||||
gap: 4px;
|
||||
align-items: start;
|
||||
}
|
||||
.f29b__transform__list {
|
||||
/* .text-line 공통 contract 그대로. wrapper 만 grid 안의 cell 역할 */
|
||||
}
|
||||
.f29b__transform__arrow {
|
||||
align-self: center;
|
||||
width: 28px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.f29b__transform__arrow img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.f29b__footnote {
|
||||
font-size: var(--font-caption); /* 10px */
|
||||
line-height: var(--lh-caption);
|
||||
color: #333;
|
||||
padding-left: 14px;
|
||||
margin-top: 1px;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
.f29b__aster-small { font-size: 9px; }
|
||||
</style>
|
||||
|
||||
<div class="f29b" data-frame-id="1171281210" data-template-id="process_product_two_way">
|
||||
|
||||
{# H2 mid-heading — section.title 렌더 (frame 13 의 f13b__title 과 동일 위계) #}
|
||||
<div class="f29b__title">{{ slot_payload.title }}</div>
|
||||
|
||||
{# Banners (PROMOTED 구조 + gradient lines 101-113).
|
||||
배경 = .f29b__banner--left/right 의 CSS gradient (figma SVG → R8 CSS gradient 재현). #}
|
||||
<div class="f29b__banners">
|
||||
<div class="f29b__banner f29b__banner--left">
|
||||
<div class="f29b__banner-text">{{ slot_payload.banner_left }}</div>
|
||||
</div>
|
||||
<div class="f29b__banner f29b__banner--right">
|
||||
<div class="f29b__banner-text">{{ slot_payload.banner_right }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Body — 6 cell grid (row-major: row 1 좌/우, row 2 좌/우, row 3 좌/우).
|
||||
row 별 height = max(좌, 우) → divider Y 정렬.
|
||||
배경 = .f29b__body 의 CSS multi-gradient (figma SVG → R8 CSS gradient 재현). #}
|
||||
<div class="f29b__body">
|
||||
|
||||
<div class="f29b__grid">
|
||||
|
||||
{# ───── Row 1: section 1 ───── #}
|
||||
{% set s1 = slot_payload.process.sections[0] %}
|
||||
<div class="f29b__cell f29b__cell--left" data-frame-slot-id="process_column">
|
||||
{% if s1.title %}
|
||||
<div class="f29b__section-title">{{ s1.title | safe }}</div>
|
||||
{% if s1.transforms %}
|
||||
<div class="transform-block">
|
||||
<div class="transform-block__header">
|
||||
<span class="transform-block__label--from">AS-IS</span>
|
||||
<span></span>
|
||||
<span class="transform-block__label--to">TO-BE</span>
|
||||
</div>
|
||||
<div class="transform-rows">
|
||||
{% for t in s1.transforms %}
|
||||
<div class="transform-row">
|
||||
<div class="transform-row__from">{{ t.from | safe }}</div>
|
||||
<div class="transform-row__arrow">➜</div>
|
||||
<div class="transform-row__to">{{ t.to | safe }}</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% elif s1.text_lines %}
|
||||
{% for line in s1.text_lines %}<div class="text-line text-line--bullet{% if line.indent > 0 %} text-line--indent-{{ line.indent }}{% endif %}">{{ line.text | safe }}</div>{% endfor %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% set p1 = slot_payload.product.sections[0] %}
|
||||
<div class="f29b__cell f29b__cell--right" data-frame-slot-id="product_column">
|
||||
{% if p1.title %}
|
||||
<div class="f29b__section-title">{{ p1.title | safe }}</div>
|
||||
{% for line in p1.text_lines %}<div class="text-line text-line--bullet{% if line.indent > 0 %} text-line--indent-{{ line.indent }}{% endif %}">{{ line.text | safe }}</div>{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{# ───── Row 2: section 2 ───── #}
|
||||
{% set s2 = slot_payload.process.sections[1] %}
|
||||
<div class="f29b__cell f29b__cell--left" data-frame-slot-id="process_column">
|
||||
{% if s2.title %}
|
||||
<div class="f29b__section-title">{{ s2.title | safe }}</div>
|
||||
{% for line in s2.text_lines %}<div class="text-line text-line--bullet{% if line.indent > 0 %} text-line--indent-{{ line.indent }}{% endif %}">{{ line.text | safe }}</div>{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% set p2 = slot_payload.product.sections[1] %}
|
||||
<div class="f29b__cell f29b__cell--right" data-frame-slot-id="product_column">
|
||||
{% if p2.title %}
|
||||
<div class="f29b__section-title">{{ p2.title | safe }}</div>
|
||||
{% for line in p2.text_lines %}<div class="text-line text-line--bullet{% if line.indent > 0 %} text-line--indent-{{ line.indent }}{% endif %}">{{ line.text | safe }}</div>{% endfor %}
|
||||
{% if p2.footnote %}
|
||||
<div class="f29b__footnote"><span class="f29b__aster-small">*</span> {{ p2.footnote | safe }}</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{# ───── Row 3: section 3 ───── #}
|
||||
{% set s3 = slot_payload.process.sections[2] %}
|
||||
<div class="f29b__cell f29b__cell--left" data-frame-slot-id="process_column">
|
||||
{% if s3.title %}
|
||||
<div class="f29b__section-title">{{ s3.title | safe }}</div>
|
||||
{% for line in s3.text_lines %}<div class="text-line text-line--bullet{% if line.indent > 0 %} text-line--indent-{{ line.indent }}{% endif %}">{{ line.text | safe }}</div>{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% set p3 = slot_payload.product.sections[2] %}
|
||||
<div class="f29b__cell f29b__cell--right" data-frame-slot-id="product_column">
|
||||
{% if p3.title %}
|
||||
<div class="f29b__section-title">{{ p3.title | safe }}{% if p3.sub_title %}<span class="f29b__section-title__sub">{{ p3.sub_title | safe }}</span>{% endif %}</div>
|
||||
{% for line in p3.text_lines %}<div class="text-line text-line--bullet{% if line.indent > 0 %} text-line--indent-{{ line.indent }}{% endif %}">{{ line.text | safe }}</div>{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,135 @@
|
||||
<!-- Phase Z-2 MVP-1.5b frame-derived adapted block.
|
||||
§17 룰 — Figma 시각 언어 promote, geometry 만 zone-compatible adapt. -->
|
||||
{#
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
Visual Provenance — figma_to_html_agent/blocks/1171281209/ (frame 28)
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
Frame 28 = "현존 상용 S/W의 현실" (cards/title-plus-3-emphasis). 3 emphasis
|
||||
cards parallel — 3 problem/약점/한계 진단 (토목 전문성 부족 / 비효율성 /
|
||||
실무 적용 불가).
|
||||
|
||||
본 partial = Track A frame 7 (V4-zero catalog-completeness activation per
|
||||
Codex round 49 guardrail). V4 = matching authority 보존. Phase Z 는 runtime
|
||||
availability 만 추가.
|
||||
|
||||
PROMOTED CSS :
|
||||
- per-emphasis 경고 색 (red/orange/amber — problem theme)
|
||||
- title gradient (zone-title family)
|
||||
- bullet markers per-emphasis color
|
||||
|
||||
NOT PROMOTED : Figma source decoration / banner / texture — 보존 (figma_to_html).
|
||||
|
||||
ADAPTED : Figma absolute → flex 3-column grid + token-fixed typography.
|
||||
|
||||
slots : title, emphasis_1/2/3_label, emphasis_1/2/3_body.
|
||||
#}
|
||||
|
||||
<style>
|
||||
.f28b {
|
||||
width: 100%; height: 100%;
|
||||
display: flex; flex-direction: column;
|
||||
gap: 6px;
|
||||
font-family: 'Noto Sans KR', 'Pretendard', sans-serif;
|
||||
word-break: keep-all;
|
||||
}
|
||||
.f28b__title {
|
||||
font-size: var(--font-zone-title);
|
||||
font-weight: 700;
|
||||
line-height: var(--lh-zone-title);
|
||||
background-image: linear-gradient(180deg, #000 0%, #883700 100%);
|
||||
-webkit-background-clip: text; background-clip: text;
|
||||
color: transparent;
|
||||
flex-shrink: 0;
|
||||
filter: drop-shadow(0 0 3px rgba(50,44,30,0.4));
|
||||
}
|
||||
|
||||
.f28b__cols {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
gap: 10px;
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
}
|
||||
.f28b__col {
|
||||
display: flex; flex-direction: column;
|
||||
border: 2px solid;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
background: #fff;
|
||||
min-height: 0;
|
||||
}
|
||||
/* per-emphasis problem theme — orange/red family for 약점/한계 진단 */
|
||||
.f28b__col:nth-child(1) { border-color: #dc2626; } /* red */
|
||||
.f28b__col:nth-child(2) { border-color: #ea580c; } /* orange */
|
||||
.f28b__col:nth-child(3) { border-color: #d97706; } /* amber */
|
||||
|
||||
.f28b__header {
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
font-size: var(--font-sub-title);
|
||||
line-height: 1.15;
|
||||
padding: 6px 10px;
|
||||
text-align: center;
|
||||
flex-shrink: 0;
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
.f28b__col:nth-child(1) .f28b__header { background: linear-gradient(180deg, #dc2626 0%, #991b1b 100%); }
|
||||
.f28b__col:nth-child(2) .f28b__header { background: linear-gradient(180deg, #ea580c 0%, #9a3412 100%); }
|
||||
.f28b__col:nth-child(3) .f28b__header { background: linear-gradient(180deg, #d97706 0%, #92400e 100%); }
|
||||
|
||||
.f28b__body {
|
||||
flex: 1 1 auto;
|
||||
overflow: hidden;
|
||||
padding: 6px 10px 8px;
|
||||
color: #1a1a1a;
|
||||
min-height: 0;
|
||||
display: flex; flex-direction: column;
|
||||
gap: 3px;
|
||||
}
|
||||
.f28b__body .text-line {
|
||||
color: inherit;
|
||||
font-size: var(--font-body);
|
||||
line-height: var(--lh-body);
|
||||
position: relative;
|
||||
padding-left: 14px;
|
||||
}
|
||||
.f28b__body .text-line--bullet::before {
|
||||
content: "!";
|
||||
position: absolute;
|
||||
left: 4px; top: 0;
|
||||
font-weight: 700;
|
||||
}
|
||||
.f28b__col:nth-child(1) .f28b__body .text-line--bullet::before { color: #dc2626; }
|
||||
.f28b__col:nth-child(2) .f28b__body .text-line--bullet::before { color: #ea580c; }
|
||||
.f28b__col:nth-child(3) .f28b__body .text-line--bullet::before { color: #d97706; }
|
||||
</style>
|
||||
|
||||
<div class="f28b" data-frame-id="1171281209" data-template-id="sw_reality_three_emphasis">
|
||||
<div class="f28b__title">{{ slot_payload.title }}</div>
|
||||
<div class="f28b__cols">
|
||||
<div class="f28b__col">
|
||||
<div class="f28b__header">{{ slot_payload.emphasis_1_label | safe }}</div>
|
||||
<div class="f28b__body">
|
||||
{% if slot_payload.emphasis_1_body %}
|
||||
{% for line in slot_payload.emphasis_1_body %}<div class="text-line text-line--bullet{% if line.indent > 0 %} text-line--indent-{{ line.indent }}{% endif %}">{{ line.text | safe }}</div>{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="f28b__col">
|
||||
<div class="f28b__header">{{ slot_payload.emphasis_2_label | safe }}</div>
|
||||
<div class="f28b__body">
|
||||
{% if slot_payload.emphasis_2_body %}
|
||||
{% for line in slot_payload.emphasis_2_body %}<div class="text-line text-line--bullet{% if line.indent > 0 %} text-line--indent-{{ line.indent }}{% endif %}">{{ line.text | safe }}</div>{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="f28b__col">
|
||||
<div class="f28b__header">{{ slot_payload.emphasis_3_label | safe }}</div>
|
||||
<div class="f28b__body">
|
||||
{% if slot_payload.emphasis_3_body %}
|
||||
{% for line in slot_payload.emphasis_3_body %}<div class="text-line text-line--bullet{% if line.indent > 0 %} text-line--indent-{{ line.indent }}{% endif %}">{{ line.text | safe }}</div>{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,157 @@
|
||||
<!-- Phase Z-2 MVP-1.5b frame-derived adapted block.
|
||||
§17 룰 — Figma 시각 언어 promote, geometry 만 zone-compatible adapt. -->
|
||||
{#
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
Visual Provenance — figma_to_html_agent/blocks/1171281190/index.html
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
PROMOTED (Figma 1:1 변환물 → 그대로 사용):
|
||||
- tech bar gradient : line 71 → linear-gradient(180deg, #0D78D0 0%, #023056 100%)
|
||||
- people bar gradient : line 72 → linear-gradient(180deg, #FF9A23 0%, #CC5200 100%)
|
||||
- nature bar gradient : line 73 → linear-gradient(180deg, #39BE49 21%, #23742C 100%)
|
||||
- tech heading text : line 123 → linear-gradient(180deg, #0D78D0, #134D7F)
|
||||
- people heading text : line 124 → linear-gradient(180deg, #FE900C, #D18B37)
|
||||
- nature heading text : line 125 → linear-gradient(180deg, #3CA649, #23742C)
|
||||
- title gradient : line 40 → linear-gradient(180deg, #000, #883700)
|
||||
- desc color : line 118 → #3E3523
|
||||
- col 외곽 border : line 57 → 2px solid #000 (top + bottom)
|
||||
- col-section divider : line 103 → 2px dashed #000
|
||||
|
||||
NOT PROMOTED (Figma 데코지만 MDX 에 없으므로 주입 X):
|
||||
- 한자 (技/術 / 人/材 / 天/地) ← MDX 에 없는 content. Figma frame 의 visual 데코일 뿐.
|
||||
|
||||
ADAPTED:
|
||||
- Figma px / native size 무시, flex layout
|
||||
- Figma 70/50/45/35px fonts → token-fixed (zone-title 13 / sub-title 12 / body 11 / caption 10)
|
||||
- desc <br>-joined → nested <ul><li> (구조 보존)
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
slots: title, pillars[].{label, color_class, sections[].{heading, bullets[]}}
|
||||
#}
|
||||
|
||||
<style>
|
||||
.f13b {
|
||||
width: 100%; height: 100%;
|
||||
display: flex; flex-direction: column;
|
||||
gap: 4px;
|
||||
font-family: 'Noto Sans KR', 'Pretendard', sans-serif;
|
||||
word-break: keep-all;
|
||||
}
|
||||
.f13b__title {
|
||||
font-size: var(--font-zone-title);
|
||||
font-weight: 700;
|
||||
line-height: var(--lh-zone-title);
|
||||
background-image: linear-gradient(180deg, #000 0%, #883700 100%);
|
||||
-webkit-background-clip: text; background-clip: text;
|
||||
color: transparent;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.f13b__cols {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
gap: 8px;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
.f13b__col {
|
||||
display: flex;
|
||||
border-top: 2px solid #000; /* PROMOTED line 57 */
|
||||
border-bottom: 2px solid #000;
|
||||
overflow: hidden;
|
||||
min-width: 0;
|
||||
background: rgba(255,255,255,0.5);
|
||||
}
|
||||
.f13b__bar {
|
||||
flex: 0 0 50px;
|
||||
display: flex; flex-direction: column;
|
||||
align-items: center; justify-content: center;
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
text-align: center;
|
||||
padding: 6px 2px;
|
||||
gap: 3px;
|
||||
}
|
||||
.f13b__col--tech .f13b__bar { background: linear-gradient(180deg, #0D78D0 0%, #023056 100%); }
|
||||
.f13b__col--people .f13b__bar { background: linear-gradient(180deg, #FF9A23 0%, #CC5200 100%); }
|
||||
.f13b__col--nature .f13b__bar { background: linear-gradient(180deg, #39BE49 21%, #23742C 100%); }
|
||||
/* PROMOTED Figma frame 13 line 92-93 — main + parenthetical stacked vertically */
|
||||
.f13b__bar-main {
|
||||
font-size: var(--font-sub-title); /* 12px — main word "기술/사람/자연" */
|
||||
font-weight: 700;
|
||||
line-height: 1.2;
|
||||
display: block;
|
||||
}
|
||||
.f13b__bar-paren {
|
||||
font-size: var(--font-caption); /* 10px — "(디지털/역량/여건)" */
|
||||
font-weight: 500;
|
||||
line-height: 1.2;
|
||||
display: block;
|
||||
opacity: 0.95;
|
||||
}
|
||||
|
||||
.f13b__body {
|
||||
flex: 1;
|
||||
display: flex; flex-direction: column;
|
||||
padding: 8px 12px; /* breathing (was 6px 10px) */
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
.f13b__section {
|
||||
flex: 1;
|
||||
padding: 6px 0; /* breathing (was 4px) */
|
||||
overflow: hidden;
|
||||
min-height: 0;
|
||||
}
|
||||
.f13b__section + .f13b__section {
|
||||
border-top: 2px dashed #000; /* PROMOTED line 103 */
|
||||
margin-top: 6px; /* visible section gap (was 4px) */
|
||||
padding-top: 8px; /* breathing (was 6px) */
|
||||
}
|
||||
/* heading — 부소목차 (사용자 5-layer 직설 2026-05-07): Digital 기술과... 같은 깊이 1 굵은 bullet */
|
||||
.f13b__heading {
|
||||
font-size: var(--font-sub-title); /* 12px — 부소목차 위계 */
|
||||
font-weight: 700;
|
||||
line-height: var(--lh-sub-title);
|
||||
-webkit-background-clip: text; background-clip: text;
|
||||
color: transparent;
|
||||
margin-bottom: 6px; /* visible heading-body gap (was 4px) */
|
||||
}
|
||||
.f13b__col--tech .f13b__heading { background-image: linear-gradient(180deg, #0D78D0 0%, #134D7F 100%); }
|
||||
.f13b__col--people .f13b__heading { background-image: linear-gradient(180deg, #FE900C 0%, #D18B37 100%); }
|
||||
.f13b__col--nature .f13b__heading { background-image: linear-gradient(180deg, #3CA649 21%, #23742C 100%); }
|
||||
|
||||
/* desc — frame-family text layout contract (.text-line 공통 클래스 사용)
|
||||
feedback (mvp1.5b_test5): browser-native ul/li 폐기. */
|
||||
.f13b__desc {
|
||||
color: #3E3523; /* PROMOTED line 118 */
|
||||
overflow: hidden;
|
||||
}
|
||||
/* desc 안 .text-line 색 override */
|
||||
.f13b__desc .text-line { color: #3E3523; }
|
||||
</style>
|
||||
|
||||
<div class="f13b" data-frame-id="1171281190" data-template-id="three_parallel_requirements">
|
||||
<div class="f13b__title">{{ slot_payload.title }}</div>
|
||||
<div class="f13b__cols">
|
||||
{% for pillar in slot_payload.pillars %}
|
||||
<div class="f13b__col f13b__col--{{ pillar.color_class }}">
|
||||
<div class="f13b__bar">
|
||||
<span class="f13b__bar-main">{{ pillar.label_main | safe }}</span>
|
||||
{% if pillar.label_paren %}
|
||||
<span class="f13b__bar-paren">{{ pillar.label_paren | safe }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="f13b__body">
|
||||
{% for section in pillar.sections %}
|
||||
<div class="f13b__section">
|
||||
<div class="f13b__heading">{{ section.heading | safe }}</div>
|
||||
{% if section.text_lines %}
|
||||
<div class="f13b__desc">
|
||||
{% for line in section.text_lines %}<div class="text-line text-line--bullet{% if line.indent > 0 %} text-line--indent-{{ line.indent }}{% endif %}">{{ line.text | safe }}</div>{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,248 @@
|
||||
<!-- Phase Z-2 MVP-1.5b frame-derived adapted block.
|
||||
§17 룰 — Figma 시각 언어 promote, geometry 만 zone-compatible adapt. -->
|
||||
{#
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
Visual Provenance — figma_to_html_agent/blocks/1171281191/ (frame 14)
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
Frame 14 = "주체별 기대효과" (cards-3col-persona, 2601×1927 px, scale 0.49213).
|
||||
3 컬럼 카드 : 발주자 / 시공자 / 설계자 각 persona 별 *목표* + bullet 7 개 안팎.
|
||||
본 partial 은 `figma_to_html_agent/blocks/1171281191/index.html` (184 lines) 을
|
||||
base 로 Phase Z 규약 (Jinja slot + token CSS + slide-base wrap) adapt.
|
||||
|
||||
본 commit (Track A 1/16 second refinement, F2 re-do post-Codex round 22 catch) :
|
||||
asset-promotion policy = per-asset case-by-case (round 13 §2.3 + round 24 합의).
|
||||
strict CSS-only over-generalization (first refinement `2fcd8bb`) 정정.
|
||||
|
||||
PROMOTED — RASTER (Phase Z `copy_assets()` 가 figma_to_html_agent/blocks/1171281191/
|
||||
assets/ → {run_dir}/assets/three_persona_benefits/ 복사) :
|
||||
- col_bg_texture (4a17cd1d...png) — 3 컬럼 BG 텍스처. CSS noise/gradient 근사 보다 fidelity 보존.
|
||||
- bottom photo client (d2c070f2...png) — 발주자 카드 하단 사진
|
||||
- bottom photo constructor (2a6a58e7...png) — 시공자 카드 하단 사진
|
||||
- bottom photo designer (39113493...png) — 설계자 카드 하단 사진
|
||||
- badge outer client (77f31997...png) — 발주자 round badge outer ring
|
||||
- badge inner client (e64c967d...png) — 발주자 round badge inner disk
|
||||
- badge outer constructor (1550ec75...png)
|
||||
- badge inner constructor (85beaf9d...png)
|
||||
- badge outer designer (9ac089fa...png)
|
||||
- badge inner designer (4b534ccf...png)
|
||||
→ 10 raster (1 BG + 3 photos + 6 badge). Codex round 24 tightening : badge =
|
||||
default promote (asset-capable path 검증).
|
||||
|
||||
PROMOTED — CSS (Figma 색/디자인 의도 → CSS 으로 충분) :
|
||||
- 발주자 accent color : Figma TEXT #285b4a (dark green) — index.html L80
|
||||
- 시공자 accent color : Figma TEXT #445a2f (olive) — index.html L81
|
||||
- 설계자 accent color : Figma TEXT #743002 (red-brown) — index.html L82
|
||||
- col-overlay tint : #d6e7c4 / #e1efe1 / #d0c0ad (opacity-80 — solid 색, CSS equivalent)
|
||||
- title gradient : #000 → #883700 (F13 zone-title 와 동일 family)
|
||||
- bullet check marker : ✓ unicode (실제 png 6896d5c2 와 동등)
|
||||
|
||||
NOT PROMOTED (MDX 무관 + Figma 데코) :
|
||||
- 한자/장식 텍스트 (Figma 안 deco) — index.html 에도 없음. N/A.
|
||||
|
||||
ADAPTED :
|
||||
- Figma 65/50/40px → token-fixed (zone-title 13 / sub-title 12 / caption / body 11)
|
||||
- Figma 396×397 absolute round badge → flex card-header 안 round image
|
||||
- Figma `zoom: 0.49213` absolute positioning → Phase Z flex column (zone fit)
|
||||
- Figma 7 bullets absolute layout → flex column gap auto spacing
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
min_height_px derivation (round 13 §2.2 — derive + confirm) :
|
||||
Figma frame 1927 px @ scale 0.49213 → 948 px adapted (full Figma fit).
|
||||
Phase Z slide-body ≤ 585 px → adaptive content fit.
|
||||
Content density (3 col × 7 bullets + badge + photo) → F29 (345) 보다 약간 ↑.
|
||||
Derived = 320 (badge 30 + bullet body ~210 + photo strip ~50 + padding 30).
|
||||
Confirm via smoke + V2 validation (MDX 02 sample run).
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
slots : title, personas[].{label, body, color_class}
|
||||
- color_class ∈ {client, constructor, designer} (role_order 따라)
|
||||
- body = list[{text:str, indent:int}] (parse_quadrant_item 출력)
|
||||
- persona suffix "목표" = frame 의 visual 언어 (slot 미사용, partial 노출)
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
Asset path runtime resolution :
|
||||
Phase Z `copy_assets(template_id, run_dir)` (phase_z2_pipeline.py:746) copies
|
||||
figma_to_html_agent/blocks/1171281191/assets/ → {run_dir}/assets/three_persona_benefits/
|
||||
→ partial 의 src="assets/three_persona_benefits/<filename>.png" 가 runtime 에서 resolve.
|
||||
#}
|
||||
|
||||
<style>
|
||||
.f14b {
|
||||
width: 100%; height: 100%;
|
||||
display: flex; flex-direction: column;
|
||||
gap: 6px;
|
||||
font-family: 'Noto Sans KR', 'Pretendard', sans-serif;
|
||||
word-break: keep-all;
|
||||
}
|
||||
.f14b__title {
|
||||
font-size: var(--font-zone-title);
|
||||
font-weight: 700;
|
||||
line-height: var(--lh-zone-title);
|
||||
background-image: linear-gradient(180deg, #000 0%, #883700 100%);
|
||||
-webkit-background-clip: text; background-clip: text;
|
||||
color: transparent;
|
||||
flex-shrink: 0;
|
||||
filter: drop-shadow(0 0 3px rgba(50,44,30,0.4));
|
||||
}
|
||||
.f14b__cols {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
gap: 10px;
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
}
|
||||
.f14b__col {
|
||||
position: relative;
|
||||
display: flex; flex-direction: column;
|
||||
border: 2px solid;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
min-height: 0;
|
||||
isolation: isolate;
|
||||
}
|
||||
/* col-bg 텍스처 (PROMOTED raster) */
|
||||
.f14b__col::before {
|
||||
content: ""; position: absolute; inset: 0;
|
||||
background: url("assets/three_persona_benefits/4a17cd1dddaba8a220b706df3ec052d2bfde4f47.png") center/cover no-repeat;
|
||||
opacity: 0.6;
|
||||
z-index: -2;
|
||||
}
|
||||
/* col-overlay (CSS solid tint per persona — index.html L44-47) */
|
||||
.f14b__col::after {
|
||||
content: ""; position: absolute; inset: 0;
|
||||
opacity: 0.8;
|
||||
z-index: -1;
|
||||
}
|
||||
.f14b__col--client { border-color: #285b4a; }
|
||||
.f14b__col--constructor { border-color: #445a2f; }
|
||||
.f14b__col--designer { border-color: #743002; }
|
||||
.f14b__col--client::after { background: #d6e7c4; } /* PROMOTED CSS */
|
||||
.f14b__col--constructor::after { background: #e1efe1; } /* PROMOTED CSS */
|
||||
.f14b__col--designer::after { background: #d0c0ad; } /* PROMOTED CSS */
|
||||
|
||||
/* badge — PROMOTED raster (outer + inner ring image, name + 목표 text overlay) */
|
||||
.f14b__badge {
|
||||
position: relative;
|
||||
display: flex; flex-direction: column;
|
||||
align-items: center; justify-content: center;
|
||||
padding: 6px;
|
||||
flex-shrink: 0;
|
||||
aspect-ratio: 1 / 1;
|
||||
width: 70px; height: 70px;
|
||||
margin: 6px auto 4px;
|
||||
}
|
||||
.f14b__badge-outer, .f14b__badge-inner {
|
||||
position: absolute; inset: 0;
|
||||
width: 100%; height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
.f14b__badge-inner {
|
||||
width: 78%; height: 78%;
|
||||
top: 11%; left: 11%;
|
||||
}
|
||||
.f14b__badge-text {
|
||||
position: relative; z-index: 1;
|
||||
display: flex; flex-direction: column;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
line-height: 1;
|
||||
}
|
||||
.f14b__badge-name {
|
||||
font-size: var(--font-caption);
|
||||
font-weight: 700;
|
||||
letter-spacing: -0.04em;
|
||||
}
|
||||
.f14b__badge-suffix {
|
||||
font-size: 0.65rem;
|
||||
font-weight: 500;
|
||||
margin-top: 2px;
|
||||
opacity: 0.85;
|
||||
}
|
||||
.f14b__col--client .f14b__badge-text { color: #285b4a; }
|
||||
.f14b__col--constructor .f14b__badge-text { color: #445a2f; }
|
||||
.f14b__col--designer .f14b__badge-text { color: #743002; }
|
||||
|
||||
/* body — bullet list. check marker CSS (PROMOTED CSS, raster 6896d5c2 와 동등) */
|
||||
.f14b__body {
|
||||
flex: 1 1 auto;
|
||||
overflow: hidden;
|
||||
padding: 4px 10px;
|
||||
color: #1a1a1a;
|
||||
min-height: 0;
|
||||
display: flex; flex-direction: column;
|
||||
gap: 3px;
|
||||
}
|
||||
.f14b__body .text-line {
|
||||
color: inherit;
|
||||
font-size: var(--font-body);
|
||||
line-height: var(--lh-body);
|
||||
position: relative;
|
||||
padding-left: 14px;
|
||||
}
|
||||
.f14b__body .text-line--bullet::before {
|
||||
content: "\2713";
|
||||
position: absolute;
|
||||
left: 0; top: 0;
|
||||
font-weight: 700;
|
||||
}
|
||||
.f14b__col--client .f14b__body .text-line--bullet::before { color: #285b4a; }
|
||||
.f14b__col--constructor .f14b__body .text-line--bullet::before { color: #445a2f; }
|
||||
.f14b__col--designer .f14b__body .text-line--bullet::before { color: #743002; }
|
||||
|
||||
/* bottom photo — PROMOTED raster (per persona 실사 사진, CSS 불가) */
|
||||
.f14b__photo {
|
||||
flex-shrink: 0;
|
||||
width: 100%; height: 36px;
|
||||
overflow: hidden;
|
||||
border-radius: 0 0 8px 8px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
.f14b__photo img {
|
||||
width: 100%; height: 100%;
|
||||
object-fit: cover;
|
||||
opacity: 0.7; /* index.html L53 — opacity 0.70 */
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="f14b" data-frame-id="1171281191" data-template-id="three_persona_benefits">
|
||||
<div class="f14b__title">{{ slot_payload.title }}</div>
|
||||
<div class="f14b__cols">
|
||||
{% for persona in slot_payload.personas %}
|
||||
<div class="f14b__col f14b__col--{{ persona.color_class }}">
|
||||
{# badge — raster outer/inner + CSS text overlay #}
|
||||
<div class="f14b__badge">
|
||||
{% if persona.color_class == "client" %}
|
||||
<img class="f14b__badge-outer" src="assets/three_persona_benefits/77f319979c880da34ff3d423fcd97827f636c01e.png" alt="">
|
||||
<img class="f14b__badge-inner" src="assets/three_persona_benefits/e64c967dd00302bfbef6cfbcbb4f7a4db5d9d96c.png" alt="">
|
||||
{% elif persona.color_class == "constructor" %}
|
||||
<img class="f14b__badge-outer" src="assets/three_persona_benefits/1550ec755fa7922dcfc1c90135a570d6b9df82cc.png" alt="">
|
||||
<img class="f14b__badge-inner" src="assets/three_persona_benefits/85beaf9dfc17b7ed4620729a086ba22143606517.png" alt="">
|
||||
{% elif persona.color_class == "designer" %}
|
||||
<img class="f14b__badge-outer" src="assets/three_persona_benefits/9ac089fa9c5106b6b26d47727003641bb56ba4b0.png" alt="">
|
||||
<img class="f14b__badge-inner" src="assets/three_persona_benefits/4b534ccf4e945fbe7436a0d8d96a6deffcfe5cef.png" alt="">
|
||||
{% endif %}
|
||||
<div class="f14b__badge-text">
|
||||
<span class="f14b__badge-name">{{ persona.label | safe }}</span>
|
||||
<span class="f14b__badge-suffix">목표</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# body — bullets with CSS check marker #}
|
||||
<div class="f14b__body">
|
||||
{% if persona.body %}
|
||||
{% for line in persona.body %}<div class="text-line text-line--bullet{% if line.indent > 0 %} text-line--indent-{{ line.indent }}{% endif %}">{{ line.text | safe }}</div>{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{# bottom photo — per persona 실사 사진 #}
|
||||
<div class="f14b__photo">
|
||||
{% if persona.color_class == "client" %}
|
||||
<img src="assets/three_persona_benefits/d2c070f200af83f563976b6b0f309d38321d204d.png" alt="">
|
||||
{% elif persona.color_class == "constructor" %}
|
||||
<img src="assets/three_persona_benefits/2a6a58e7bf7a645b5ede65115feb2890ccc414d1.png" alt="">
|
||||
{% elif persona.color_class == "designer" %}
|
||||
<img src="assets/three_persona_benefits/39113493f6e3ae76d766e86e293b0f0dcbf55d91.png" alt="">
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
@@ -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
|
||||
@@ -0,0 +1,121 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Phase Z 8-preset Layout Catalog Preview</title>
|
||||
<style>
|
||||
body { font-family: 'Pretendard', 'Noto Sans KR', sans-serif; padding: 24px; max-width: 1400px; margin: 0 auto; background: #f1f5f9; color: #1e293b; }
|
||||
h1 { border-bottom: 2px solid #333; padding-bottom: 8px; margin-top: 0; }
|
||||
.grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 24px; margin-top: 24px; }
|
||||
.card { background: #fff; border: 1px solid #cbd5e1; border-radius: 8px; padding: 16px; box-shadow: 0 2px 8px rgba(0,0,0,0.05); }
|
||||
.card h2 { margin-top: 0; font-size: 18px; display: flex; justify-content: space-between; align-items: center; }
|
||||
.badge { font-size: 11px; font-weight: 600; padding: 2px 8px; border-radius: 999px; }
|
||||
.badge.default-selection { background: #dcfce7; color: #166534; }
|
||||
.badge.alternative { background: #e2e8f0; color: #475569; }
|
||||
.meta { font-size: 13px; color: #64748b; margin-bottom: 12px; }
|
||||
.meta code { background: #f1f5f9; padding: 1px 6px; border-radius: 3px; }
|
||||
.preview { width: 100%; aspect-ratio: 16/9; border: 1px solid #94a3b8; background: #fafafa; padding: 8px; box-sizing: border-box; }
|
||||
.zone { background: #dbeafe; border: 2px solid #3b82f6; display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 700; color: #1e40af; padding: 4px; box-sizing: border-box; }
|
||||
.zone:nth-child(2) { background: #fef3c7; border-color: #f59e0b; color: #92400e; }
|
||||
.zone:nth-child(3) { background: #dcfce7; border-color: #16a34a; color: #166534; }
|
||||
.zone:nth-child(4) { background: #fce7f3; border-color: #db2777; color: #9f1239; }
|
||||
.when { margin-top: 12px; font-size: 13px; }
|
||||
.when strong { color: #475569; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>Phase Z 8-preset Layout Catalog</h1>
|
||||
<p>source: <code>templates/phase_z2/layouts/layouts.yaml</code> / 사람이 8 layout 시각 검증용. <strong>default selection</strong> = 현재 select_layout_preset() 단일 결정 로직에서 자동 선택. <strong>alternative</strong> = render_ready 이지만 자동 선택 안 됨 (Step 7-B 후보 활성화 대상).</p>
|
||||
|
||||
<div class="grid">
|
||||
|
||||
<div class="card">
|
||||
<h2>single <span class="badge default-selection">default selection</span></h2>
|
||||
<div class="meta">zones: 1 / topology: single / positions: <code>[primary]</code></div>
|
||||
<div class="preview" style="display:grid; grid-template-areas:'primary'; grid-template-columns:1fr; grid-template-rows:1fr; gap:8px;">
|
||||
<div class="zone" style="grid-area:primary;">primary</div>
|
||||
</div>
|
||||
<div class="when"><strong>candidate_when:</strong> unit_count = 1</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>horizontal-2 <span class="badge default-selection">default selection</span></h2>
|
||||
<div class="meta">zones: 2 / topology: rows / positions: <code>[top, bottom]</code></div>
|
||||
<div class="preview" style="display:grid; grid-template-areas:'top' 'bottom'; grid-template-columns:1fr; grid-template-rows:1fr 1fr; gap:8px;">
|
||||
<div class="zone" style="grid-area:top;">top</div>
|
||||
<div class="zone" style="grid-area:bottom;">bottom</div>
|
||||
</div>
|
||||
<div class="when"><strong>candidate_when:</strong> unit_count = 2 / orientation = horizontal</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>vertical-2 <span class="badge alternative">alternative</span></h2>
|
||||
<div class="meta">zones: 2 / topology: cols / positions: <code>[left, right]</code></div>
|
||||
<div class="preview" style="display:grid; grid-template-areas:'left right'; grid-template-columns:1fr 1fr; grid-template-rows:1fr; gap:8px;">
|
||||
<div class="zone" style="grid-area:left;">left</div>
|
||||
<div class="zone" style="grid-area:right;">right</div>
|
||||
</div>
|
||||
<div class="when"><strong>candidate_when:</strong> unit_count = 2 / orientation = vertical</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>top-1-bottom-2 <span class="badge default-selection">default selection</span></h2>
|
||||
<div class="meta">zones: 3 / topology: T / positions: <code>[top, bottom-left, bottom-right]</code></div>
|
||||
<div class="preview" style="display:grid; grid-template-areas:'top top' 'bottom-left bottom-right'; grid-template-columns:1fr 1fr; grid-template-rows:1fr 1fr; gap:8px;">
|
||||
<div class="zone" style="grid-area:top;">top</div>
|
||||
<div class="zone" style="grid-area:bottom-left;">bottom-left</div>
|
||||
<div class="zone" style="grid-area:bottom-right;">bottom-right</div>
|
||||
</div>
|
||||
<div class="when"><strong>candidate_when:</strong> unit_count = 3 / layout = T</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>top-2-bottom-1 <span class="badge alternative">alternative</span></h2>
|
||||
<div class="meta">zones: 3 / topology: inverted-T / positions: <code>[top-left, top-right, bottom]</code></div>
|
||||
<div class="preview" style="display:grid; grid-template-areas:'top-left top-right' 'bottom bottom'; grid-template-columns:1fr 1fr; grid-template-rows:1fr 1fr; gap:8px;">
|
||||
<div class="zone" style="grid-area:top-left;">top-left</div>
|
||||
<div class="zone" style="grid-area:top-right;">top-right</div>
|
||||
<div class="zone" style="grid-area:bottom;">bottom</div>
|
||||
</div>
|
||||
<div class="when"><strong>candidate_when:</strong> unit_count = 3 / layout = inverted-T</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>left-1-right-2 <span class="badge alternative">alternative</span></h2>
|
||||
<div class="meta">zones: 3 / topology: side-T-left / positions: <code>[left, right-top, right-bottom]</code></div>
|
||||
<div class="preview" style="display:grid; grid-template-areas:'left right-top' 'left right-bottom'; grid-template-columns:1fr 1fr; grid-template-rows:1fr 1fr; gap:8px;">
|
||||
<div class="zone" style="grid-area:left;">left</div>
|
||||
<div class="zone" style="grid-area:right-top;">right-top</div>
|
||||
<div class="zone" style="grid-area:right-bottom;">right-bottom</div>
|
||||
</div>
|
||||
<div class="when"><strong>candidate_when:</strong> unit_count = 3 / layout = side-T-left</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>left-2-right-1 <span class="badge alternative">alternative</span></h2>
|
||||
<div class="meta">zones: 3 / topology: side-T-right / positions: <code>[left-top, right, left-bottom]</code></div>
|
||||
<div class="preview" style="display:grid; grid-template-areas:'left-top right' 'left-bottom right'; grid-template-columns:1fr 1fr; grid-template-rows:1fr 1fr; gap:8px;">
|
||||
<div class="zone" style="grid-area:left-top;">left-top</div>
|
||||
<div class="zone" style="grid-area:right;">right</div>
|
||||
<div class="zone" style="grid-area:left-bottom;">left-bottom</div>
|
||||
</div>
|
||||
<div class="when"><strong>candidate_when:</strong> unit_count = 3 / layout = side-T-right</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>grid-2x2 <span class="badge default-selection">default selection</span></h2>
|
||||
<div class="meta">zones: 4 / topology: 2x2 / positions: <code>[top-left, top-right, bottom-left, bottom-right]</code></div>
|
||||
<div class="preview" style="display:grid; grid-template-areas:'top-left top-right' 'bottom-left bottom-right'; grid-template-columns:1fr 1fr; grid-template-rows:1fr 1fr; gap:8px;">
|
||||
<div class="zone" style="grid-area:top-left;">top-left</div>
|
||||
<div class="zone" style="grid-area:top-right;">top-right</div>
|
||||
<div class="zone" style="grid-area:bottom-left;">bottom-left</div>
|
||||
<div class="zone" style="grid-area:bottom-right;">bottom-right</div>
|
||||
</div>
|
||||
<div class="when"><strong>candidate_when:</strong> unit_count = 4</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,166 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Phase Z Child Zone / Internal Region Catalog Preview</title>
|
||||
<style>
|
||||
body { font-family: 'Pretendard', 'Noto Sans KR', sans-serif; padding: 24px; max-width: 1400px; margin: 0 auto; background: #f1f5f9; color: #1e293b; }
|
||||
h1 { border-bottom: 2px solid #333; padding-bottom: 8px; margin-top: 0; }
|
||||
h2 { margin-top: 40px; padding: 8px 12px; background: #1e293b; color: #fff; border-radius: 4px; }
|
||||
.grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 24px; margin-top: 24px; }
|
||||
.card { background: #fff; border: 1px solid #cbd5e1; border-radius: 8px; padding: 16px; box-shadow: 0 2px 8px rgba(0,0,0,0.05); }
|
||||
.card h3 { margin-top: 0; font-size: 17px; display: flex; justify-content: space-between; align-items: center; }
|
||||
.badge { font-size: 11px; font-weight: 600; padding: 2px 8px; border-radius: 999px; }
|
||||
.badge.fallback { background: #fef3c7; color: #92400e; }
|
||||
.badge.normal { background: #e0e7ff; color: #3730a3; }
|
||||
.badge.danger { background: #fecaca; color: #991b1b; border: 1px solid #f87171; }
|
||||
.badge.safe { background: #dcfce7; color: #166534; }
|
||||
.meta { font-size: 13px; color: #64748b; margin-bottom: 12px; }
|
||||
.meta code { background: #f1f5f9; padding: 1px 6px; border-radius: 3px; }
|
||||
.preview { width: 100%; aspect-ratio: 16/9; border: 1px solid #94a3b8; background: #fafafa; padding: 8px; box-sizing: border-box; }
|
||||
.region { background: #dbeafe; border: 2px solid #3b82f6; display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 700; color: #1e40af; padding: 4px; box-sizing: border-box; }
|
||||
.region:nth-child(2) { background: #fef3c7; border-color: #f59e0b; color: #92400e; }
|
||||
.region:nth-child(3) { background: #dcfce7; border-color: #16a34a; color: #166534; }
|
||||
.region:nth-child(4) { background: #fce7f3; border-color: #db2777; color: #9f1239; }
|
||||
.when, .applies, .forbidden { margin-top: 12px; font-size: 13px; }
|
||||
.when strong, .applies strong, .forbidden strong { color: #475569; }
|
||||
.forbidden-block { background: #fef2f2; border: 2px solid #f87171; padding: 10px 12px; border-radius: 6px; margin-top: 8px; }
|
||||
.forbidden-block strong { color: #991b1b; display: block; margin-bottom: 4px; font-size: 13px; }
|
||||
.forbidden-block code { background: #fff; color: #991b1b; padding: 2px 6px; border-radius: 3px; font-weight: 600; }
|
||||
.strategy-card { background: #fff; border: 1px solid #cbd5e1; border-radius: 8px; padding: 16px; box-shadow: 0 2px 8px rgba(0,0,0,0.05); }
|
||||
.strategy-card h3 { margin-top: 0; font-size: 17px; display: flex; justify-content: space-between; align-items: center; }
|
||||
.strategy-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 24px; margin-top: 24px; }
|
||||
.strategy-card.dropped-card { border: 2px solid #f87171; background: #fef2f2; }
|
||||
.trigger-demo { position: relative; background: #f8fafc; border: 1px dashed #94a3b8; padding: 12px 16px; margin-top: 12px; border-radius: 4px; font-size: 12px; color: #475569; min-height: 70px; }
|
||||
.trigger-btn { position: absolute; top: 6px; right: 6px; background: #2563eb; color: #fff; padding: 3px 10px; border-radius: 4px; font-size: 11px; font-weight: 600; cursor: pointer; }
|
||||
.trigger-info { font-size: 11px; color: #64748b; margin-top: 6px; }
|
||||
.trigger-info code { background: #fff; padding: 1px 5px; border-radius: 2px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>Phase Z Child Zone / Internal Region Catalog</h1>
|
||||
<p>source: <code>region_layouts.yaml</code> + <code>display_strategies.yaml</code> / 사람이 두 axis (구조 + 정책) 시각 검증.</p>
|
||||
<p>SPEC: <code>docs/architecture/PHASE-Z-CONTENT-OBJECT-SUBZONE-SPEC.md §2.5</code> (region 6 entry, display 4 entry)</p>
|
||||
|
||||
<h2>1. Region Layouts (zone 안 분할 구조 — 6 entry)</h2>
|
||||
|
||||
<div class="grid">
|
||||
|
||||
<div class="card">
|
||||
<h3>region-single <span class="badge normal">1 region</span></h3>
|
||||
<div class="meta">topology: single / region_count: 1</div>
|
||||
<div class="preview" style="display:grid; grid-template-areas:'r1'; grid-template-columns:1fr; grid-template-rows:1fr; gap:8px;">
|
||||
<div class="region" style="grid-area:r1;">single region</div>
|
||||
</div>
|
||||
<div class="when"><strong>candidate_when:</strong> region_count = 1</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>region-vertical-stack <span class="badge fallback">default fallback</span></h3>
|
||||
<div class="meta">topology: vertical / region_count: 2+</div>
|
||||
<div class="preview" style="display:grid; grid-template-areas:'r1' 'r2'; grid-template-columns:1fr; grid-template-rows:1fr 1fr; gap:8px;">
|
||||
<div class="region" style="grid-area:r1;">region 1 (top)</div>
|
||||
<div class="region" style="grid-area:r2;">region 2 (bottom)</div>
|
||||
</div>
|
||||
<div class="when"><strong>candidate_when:</strong> region_count >= 2 AND flow_type = sequential. Default fallback when no other rule matches.</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>region-horizontal-split <span class="badge normal">2 region</span></h3>
|
||||
<div class="meta">topology: horizontal / region_count: 2 / has_visual_element: true</div>
|
||||
<div class="preview" style="display:grid; grid-template-areas:'r1 r2'; grid-template-columns:1fr 1fr; grid-template-rows:1fr; gap:8px;">
|
||||
<div class="region" style="grid-area:r1;">region 1 (left)</div>
|
||||
<div class="region" style="grid-area:r2;">region 2 (right)</div>
|
||||
</div>
|
||||
<div class="when"><strong>candidate_when:</strong> region_count = 2 AND visual element (image / diagram) in content_type_mix</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>region-main-support <span class="badge normal">2 region weighted</span></h3>
|
||||
<div class="meta">topology: weighted / ratios: [0.7, 0.3]</div>
|
||||
<div class="preview" style="display:grid; grid-template-areas:'r1 r2'; grid-template-columns:7fr 3fr; grid-template-rows:1fr; gap:8px;">
|
||||
<div class="region" style="grid-area:r1;">main (0.7)</div>
|
||||
<div class="region" style="grid-area:r2;">support (0.3)</div>
|
||||
</div>
|
||||
<div class="when"><strong>candidate_when:</strong> region_count = 2 AND role = [primary, supporting] AND ratio max/min >= 2</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>region-preview-details <span class="badge normal">preview + popup</span></h3>
|
||||
<div class="meta">topology: preview-details / preserves_original: true</div>
|
||||
<div class="preview" style="display:grid; grid-template-areas:'r1 r2'; grid-template-columns:2fr 1fr; grid-template-rows:1fr; gap:8px;">
|
||||
<div class="region" style="grid-area:r1;">preview (inline)</div>
|
||||
<div class="region" style="grid-area:r2;">details / popup</div>
|
||||
</div>
|
||||
<div class="when"><strong>candidate_when:</strong> details_presence = true OR large_table (>=5 rows) OR long_text. <strong style="color:#16a34a;">User lock: 원문 무손실 보존.</strong></div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>region-grid-2x2 <span class="badge normal">4 region</span></h3>
|
||||
<div class="meta">topology: grid / region_count: 4</div>
|
||||
<div class="preview" style="display:grid; grid-template-areas:'r1 r2' 'r3 r4'; grid-template-columns:1fr 1fr; grid-template-rows:1fr 1fr; gap:8px;">
|
||||
<div class="region" style="grid-area:r1;">region 1</div>
|
||||
<div class="region" style="grid-area:r2;">region 2</div>
|
||||
<div class="region" style="grid-area:r3;">region 3</div>
|
||||
<div class="region" style="grid-area:r4;">region 4</div>
|
||||
</div>
|
||||
<div class="when"><strong>candidate_when:</strong> region_count = 4 AND content type 4 equal items</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<h2>2. Display Strategies (콘텐츠 처리 정책 — 4 entry)</h2>
|
||||
|
||||
<div class="strategy-grid">
|
||||
|
||||
<div class="strategy-card">
|
||||
<h3>inline_full <span class="badge safe">all content types</span></h3>
|
||||
<div class="meta">Content fully inline — entire content rendered within region.</div>
|
||||
<div class="applies"><strong>applies_to:</strong> <code>text_block</code> <code>table</code> <code>image</code> <code>details</code> <code>decorative_element</code></div>
|
||||
<div class="applies"><strong>preserves_original:</strong> true (all inline = original is inline)</div>
|
||||
</div>
|
||||
|
||||
<div class="strategy-card">
|
||||
<h3>inline_preview_with_details <span class="badge safe">popup preserved</span></h3>
|
||||
<div class="meta">Partial inline preview + remaining in details/popup. <strong style="color:#16a34a;">User lock: 원문 popup 보존.</strong></div>
|
||||
<div class="applies"><strong>applies_to:</strong> <code>text_block</code> <code>table</code> <code>details</code></div>
|
||||
<div class="applies"><strong>preserves_original:</strong> true (popup 안에 보존)</div>
|
||||
<div class="trigger-demo">
|
||||
<div class="trigger-btn">details</div>
|
||||
<div>preview content (일부 inline)</div>
|
||||
<div>preview content ...</div>
|
||||
</div>
|
||||
<div class="trigger-info"><strong>detail_trigger:</strong> <code>placement: top-right</code> / <code>label: details</code> / 버튼은 원문 대체 X — 원문 전체 진입문</div>
|
||||
</div>
|
||||
|
||||
<div class="strategy-card">
|
||||
<h3>details_only <span class="badge safe">popup preserved</span></h3>
|
||||
<div class="meta">Summary inline only, full content in popup. <strong style="color:#16a34a;">User lock: 전체 popup 보존.</strong></div>
|
||||
<div class="applies"><strong>applies_to:</strong> <code>text_block</code> <code>table</code> <code>details</code></div>
|
||||
<div class="applies"><strong>preserves_original:</strong> true (popup)</div>
|
||||
<div class="trigger-demo">
|
||||
<div class="trigger-btn">details</div>
|
||||
<div>summary inline only</div>
|
||||
</div>
|
||||
<div class="trigger-info"><strong>detail_trigger:</strong> <code>placement: top-right</code> / <code>label: details</code> / 전체 원문 popup 안 보존</div>
|
||||
</div>
|
||||
|
||||
<div class="strategy-card dropped-card">
|
||||
<h3>dropped <span class="badge danger">decorative only</span></h3>
|
||||
<div class="meta">Decorative element omitted due to space constraints.</div>
|
||||
<div class="applies"><strong>applies_to:</strong> <code>decorative_element</code></div>
|
||||
<div class="forbidden-block">
|
||||
<strong>FORBIDDEN_FOR (절대 금지):</strong>
|
||||
<code>text_block</code> <code>table</code> <code>image</code> <code>details</code><br>
|
||||
<span style="font-size:12px; color:#7f1d1d; margin-top:4px; display:block;">
|
||||
User lock — 사용자 절대 룰. 텍스트 / 표 / 이미지 / details 콘텐츠는 절대 dropped X.<br>
|
||||
오답노트 #5 / IMPROVEMENT-REDESIGN.md §3.6 line 110 — 원문 무손실 보존.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,318 @@
|
||||
<!-- Phase Z-2 MVP-1.5b — single slide + Type B layout (top/bottom zones).
|
||||
원래 Phase Z 설계 복귀: MDX 1 = slide 1, layout preset = zone 분할, frame-derived block ⊂ zone. -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko"{% if embedded_mode == "embedded" %} class="embedded"{% endif %}>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=1280">
|
||||
<title>{{ slide_title }}</title>
|
||||
{% if embedded_mode == "auto" %}
|
||||
<script>
|
||||
(function(){
|
||||
try {
|
||||
var params = new URLSearchParams(window.location.search);
|
||||
if (params.get('embedded') === '1' || window.self !== window.top) {
|
||||
document.documentElement.classList.add('embedded');
|
||||
}
|
||||
} catch (e) {}
|
||||
})();
|
||||
</script>
|
||||
{% endif %}
|
||||
<style>
|
||||
/* ── existing tokens (inlined) ── */
|
||||
{{ token_css | safe }}
|
||||
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body {
|
||||
font-family: 'Noto Sans KR', 'Pretendard', sans-serif;
|
||||
background: #e8ecf0;
|
||||
display: flex; justify-content: center; align-items: center;
|
||||
min-height: 100vh;
|
||||
word-break: keep-all;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
/* ── IMP-14 A-4: embedded mode reset (iframe consumer) ──
|
||||
standalone-only body centering/min-height/padding undone so the .slide
|
||||
(1280×720) sits at origin without vertical shift or clipping. */
|
||||
html.embedded body {
|
||||
background: transparent;
|
||||
display: block;
|
||||
min-height: 0;
|
||||
padding: 0;
|
||||
}
|
||||
html.embedded .slide {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* ── 16:9 슬라이드 (single, 1280×720) ── */
|
||||
.slide {
|
||||
width: 1280px; height: 720px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
background: #fff;
|
||||
box-shadow: 0 4px 20px rgba(0,0,0,.15);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.slide-bg {
|
||||
position: absolute; inset: 0;
|
||||
background: linear-gradient(180deg, #f0f0f0 0%, #ffffff 100%);
|
||||
z-index: 0;
|
||||
}
|
||||
.slide-title {
|
||||
position: absolute;
|
||||
left: 52px; top: 22px;
|
||||
width: calc(100% - 104px);
|
||||
font-weight: 700;
|
||||
font-size: var(--font-slide-title);
|
||||
line-height: var(--lh-slide-title);
|
||||
background-image: linear-gradient(180deg, #296b55 0%, #123328 100%);
|
||||
-webkit-background-clip: text; background-clip: text;
|
||||
color: transparent;
|
||||
text-shadow: 0 0 2px #322c1e;
|
||||
z-index: 2;
|
||||
}
|
||||
.slide-divider {
|
||||
position: absolute;
|
||||
left: 50px; top: 58px;
|
||||
width: calc(100% - 100px);
|
||||
height: 2px;
|
||||
background: #cbd5e1;
|
||||
z-index: 2;
|
||||
}
|
||||
.slide-body {
|
||||
position: absolute;
|
||||
left: 50px; top: 76px;
|
||||
width: calc(100% - 100px); /* 1180 */
|
||||
height: 585px;
|
||||
z-index: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* ── Layout preset (composition planner v0 — 8 vocabulary) ──
|
||||
단일 .layout-{preset} 클래스에 grid CSS 주입.
|
||||
layout_css = pipeline build_layout_css() 결과 :
|
||||
- horizontal-2 : rows = dynamic px (content_weight + frame_min_height)
|
||||
- 그 외 : rows / cols = fr default (LAYOUT_PRESETS)
|
||||
positions (single / top / bottom / left / right / top-left / ... / grid-2x2 9개)
|
||||
은 .zone 의 inline grid-area 로 지정 — preset CSS 는 areas 만 정의. */
|
||||
.layout-{{ layout_preset }} {
|
||||
display: grid;
|
||||
grid-template-columns: {{ layout_css.cols }};
|
||||
grid-template-rows: {{ layout_css.rows }};
|
||||
grid-template-areas: {{ layout_css.areas | safe }};
|
||||
gap: {{ gap_px }}px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* ── Zone — block 가용 공간 최대화. 프레임 자체 styling 이 boundary 역할 ── */
|
||||
.zone {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
/* ── IMP-30 u5 : provisional zone marker (first-render invariant) ──
|
||||
When V4 rank-1 candidate falls outside MVP1_ALLOWED_STATUSES (chain_exhausted)
|
||||
the pipeline still renders the rank-1 frame so the first-render invariant
|
||||
holds, but the zone is tagged `provisional` so the user/AI can adapt later
|
||||
(IMP-31). Visual contract:
|
||||
- dashed amber border + striped wash → "needs adaptation" at a glance
|
||||
- inline badge top-right → text label for non-color-perceiving readers
|
||||
MDX content is preserved as-is; no shrink, no rewrite. */
|
||||
.zone--provisional {
|
||||
outline: 2px dashed #b8860b;
|
||||
outline-offset: -2px;
|
||||
background-image: repeating-linear-gradient(
|
||||
45deg,
|
||||
rgba(184, 134, 11, 0.04) 0,
|
||||
rgba(184, 134, 11, 0.04) 8px,
|
||||
transparent 8px,
|
||||
transparent 16px
|
||||
);
|
||||
}
|
||||
.zone--provisional .zone__needs-adaptation-badge {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
right: 4px;
|
||||
z-index: 10;
|
||||
padding: 2px 6px;
|
||||
background: #b8860b;
|
||||
color: #fff;
|
||||
font-size: 9px;
|
||||
font-weight: 700;
|
||||
line-height: 1.2;
|
||||
letter-spacing: 0.04em;
|
||||
border-radius: 2px;
|
||||
text-transform: uppercase;
|
||||
pointer-events: none;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
/* ── Frame-family text layout contract (shared, reusable) ──
|
||||
feedback-1 (mvp1.5b_test7): visible improvement 강화.
|
||||
Stronger hanging indent + breathing line spacing + visible hierarchy. */
|
||||
.text-line {
|
||||
font-size: var(--font-body); /* 11px */
|
||||
font-weight: var(--weight-body);
|
||||
line-height: 1.6; /* breathing room */
|
||||
margin: 0;
|
||||
}
|
||||
.text-line + .text-line {
|
||||
margin-top: 4px; /* visible gap between lines (was 2px) */
|
||||
}
|
||||
|
||||
/* bullet line — hanging indent via padding + absolute marker (안정적) */
|
||||
.text-line--bullet {
|
||||
padding-left: 14px;
|
||||
position: relative;
|
||||
}
|
||||
.text-line--bullet::before {
|
||||
content: "•"; /* visible bullet 마커 */
|
||||
position: absolute;
|
||||
left: 2px;
|
||||
top: 0;
|
||||
font-weight: 700;
|
||||
line-height: inherit;
|
||||
color: inherit;
|
||||
}
|
||||
/* indent levels — visible nested hierarchy */
|
||||
.text-line--indent-1 {
|
||||
padding-left: 30px;
|
||||
}
|
||||
.text-line--indent-1::before {
|
||||
content: "◦"; /* sub-bullet 다른 마커 */
|
||||
left: 18px;
|
||||
}
|
||||
.text-line--indent-2 {
|
||||
padding-left: 46px;
|
||||
}
|
||||
.text-line--indent-2::before {
|
||||
content: "▪";
|
||||
left: 34px;
|
||||
}
|
||||
/* body line — 마커 없음 */
|
||||
.text-line--body {
|
||||
padding-left: 0;
|
||||
}
|
||||
.text-line strong { color: #000; font-weight: 700; }
|
||||
|
||||
/* ── Transform-block family (frame 29 AS-IS/TO-BE dedicated comparison component) ──
|
||||
feedback-3: bullet rows 가 아닌 *전용 비교 component*. Header (AS-IS / TO-BE) + paired rows.
|
||||
color-coded cells, left-border accent → 단번에 *비교 구조* 인지. */
|
||||
.transform-block {
|
||||
margin-top: 4px;
|
||||
padding: 6px 8px 6px;
|
||||
background: rgba(255, 255, 255, 0.4);
|
||||
border-radius: 3px;
|
||||
border: 1px solid rgba(0,0,0,0.05);
|
||||
}
|
||||
.transform-block__header {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 22px 1fr;
|
||||
gap: 6px;
|
||||
margin-bottom: 4px;
|
||||
padding-bottom: 3px;
|
||||
border-bottom: 1px dashed rgba(0,0,0,0.12);
|
||||
font-size: 9px;
|
||||
font-weight: 900;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
.transform-block__label--from { color: #6b5444; }
|
||||
.transform-block__label--to { color: #2563eb; text-align: left; }
|
||||
.transform-rows {
|
||||
display: flex; flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
.transform-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 22px 1fr;
|
||||
gap: 6px;
|
||||
align-items: stretch;
|
||||
font-size: var(--font-body);
|
||||
line-height: 1.45;
|
||||
}
|
||||
.transform-row__from {
|
||||
padding: 3px 8px;
|
||||
background: linear-gradient(90deg, rgba(140,120,90,0.16), rgba(140,120,90,0.08));
|
||||
border-left: 2px solid #b8a98a;
|
||||
border-radius: 2px;
|
||||
color: #4b3f30;
|
||||
font-weight: 500;
|
||||
}
|
||||
.transform-row__arrow {
|
||||
text-align: center;
|
||||
color: #2563eb;
|
||||
font-weight: 900;
|
||||
font-size: 14px;
|
||||
align-self: center;
|
||||
}
|
||||
.transform-row__to {
|
||||
padding: 3px 8px;
|
||||
background: linear-gradient(90deg, rgba(37,99,235,0.10), rgba(37,99,235,0.18));
|
||||
border-left: 2px solid #2563eb;
|
||||
border-radius: 2px;
|
||||
color: #1e40af;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
/* ── Footer pill — feedback-3: body 와 weight balance, 살짝 가벼워짐 ── */
|
||||
.slide-footer {
|
||||
position: absolute;
|
||||
left: 50px; bottom: 8px;
|
||||
width: calc(100% - 100px); /* front 기준 (body 와 정렬) */
|
||||
height: 41px; /* front 기준 */
|
||||
border-radius: 999px;
|
||||
overflow: hidden;
|
||||
z-index: 2;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
background: linear-gradient(90deg, #3b3523 5%, #263a2a 50%, #113f31 95%);
|
||||
opacity: 0.92; /* slightly lighter */
|
||||
}
|
||||
.slide-footer-text {
|
||||
position: relative; z-index: 1;
|
||||
font-size: 15px; /* was 20px (--font-footer) */
|
||||
font-weight: 700;
|
||||
line-height: 1.2;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
text-shadow: 0 0 3px rgba(0,0,0,.4);
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
.slide-footer-text em { color: #fe3; font-style: normal; }
|
||||
|
||||
.phase-z2-marker {
|
||||
position: absolute;
|
||||
top: 4px; right: 8px;
|
||||
font-size: 9px; color: #94a3b8;
|
||||
font-family: monospace;
|
||||
z-index: 3;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="slide" data-page="1">
|
||||
<div class="slide-bg"></div>
|
||||
<div class="phase-z2-marker">phase_z2 / mvp-1.5b / {{ layout_preset }} / single slide</div>
|
||||
<div class="slide-title">{{ slide_title }}</div>
|
||||
<div class="slide-divider"></div>
|
||||
<div class="slide-body">
|
||||
<div class="layout-{{ layout_preset }}">
|
||||
{% for zone in zones %}
|
||||
<div class="zone{% if zone.provisional %} zone--provisional{% endif %}" data-zone-position="{{ zone.position }}" data-template-id="{{ zone.template_id }}"{% if zone.provisional %} data-provisional="1"{% endif %} style="grid-area: {{ zone.position }};">
|
||||
{% if zone.provisional %}<span class="zone__needs-adaptation-badge" aria-label="needs user or AI adaptation">needs adaptation</span>{% endif %}
|
||||
{{ zone.partial_html | safe }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% if slide_footer %}
|
||||
<div class="slide-footer">
|
||||
<div class="slide-footer-text">{{ slide_footer | safe }}</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,133 @@
|
||||
/* ══════════════════════════════════════
|
||||
slide-base.css
|
||||
══════════════════════════════════════
|
||||
슬라이드 공통 프레임 스타일.
|
||||
slide-base.html에서 분리.
|
||||
직접값 대신 토큰 변수 참조.
|
||||
══════════════════════════════════════ */
|
||||
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
|
||||
body {
|
||||
font-family: 'Noto Sans KR', sans-serif;
|
||||
background: var(--color-bg-page);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100vh;
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
/* ── 16:9 슬라이드 컨테이너 ── */
|
||||
.slide {
|
||||
width: 1280px;
|
||||
height: 720px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
background: var(--color-bg);
|
||||
box-shadow: 0 4px 20px rgba(0,0,0,0.15);
|
||||
}
|
||||
|
||||
/* ── 배경 ── */
|
||||
.slide-bg {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: linear-gradient(180deg, #f0f0f0 0%, #ffffff 100%);
|
||||
z-index: 0;
|
||||
}
|
||||
.slide-bg-texture {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
opacity: 0.02;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* ── 대목차 제목 ── */
|
||||
.slide-title {
|
||||
position: absolute;
|
||||
left: var(--slide-title-left);
|
||||
top: var(--slide-title-top);
|
||||
width: calc(100% - 104px);
|
||||
font-weight: var(--weight-slide-title);
|
||||
font-size: var(--font-slide-title);
|
||||
line-height: var(--lh-slide-title);
|
||||
background-image: linear-gradient(180deg, var(--color-slide-title-from) 0%, var(--color-slide-title-to) 100%);
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
color: transparent;
|
||||
text-shadow: 0 0 2px #322c1e;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
/* ── 구분선 ── */
|
||||
.slide-divider {
|
||||
position: absolute;
|
||||
left: 50px;
|
||||
top: var(--slide-divider-top);
|
||||
width: calc(100% - 100px);
|
||||
height: 2px;
|
||||
z-index: 2;
|
||||
}
|
||||
.slide-divider img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* ── 본문 영역 ── */
|
||||
.slide-body {
|
||||
position: absolute;
|
||||
left: var(--slide-padding-x);
|
||||
top: var(--slide-body-top);
|
||||
width: calc(100% - var(--slide-padding-x) * 2);
|
||||
height: var(--slide-body-height);
|
||||
z-index: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* ── 하단 footer pill ── */
|
||||
.slide-footer {
|
||||
position: absolute;
|
||||
left: 50px;
|
||||
bottom: var(--slide-footer-bottom);
|
||||
width: calc(100% - 100px);
|
||||
height: var(--slide-footer-height);
|
||||
border-radius: 999px;
|
||||
overflow: hidden;
|
||||
z-index: 2;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.slide-footer-bg {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
border-radius: 999px;
|
||||
z-index: 0;
|
||||
}
|
||||
.slide-footer--css {
|
||||
background: linear-gradient(90deg, var(--color-footer-bg-from) 5%, var(--color-footer-bg-mid) 50%, var(--color-footer-bg-to) 95%);
|
||||
}
|
||||
|
||||
/* ── footer 텍스트 ── */
|
||||
.slide-footer-text {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
font-size: var(--font-footer);
|
||||
font-weight: var(--weight-footer);
|
||||
line-height: var(--lh-footer);
|
||||
color: var(--color-footer-text);
|
||||
text-align: center;
|
||||
text-shadow: 0 0 4px rgba(0,0,0,0.5);
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
.slide-footer-text em {
|
||||
color: var(--color-footer-accent);
|
||||
font-style: normal;
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/* ══════════════════════════════════════
|
||||
Color Tokens v1
|
||||
══════════════════════════════════════
|
||||
2층 구조: 공통 테마색 + 블록 의미색.
|
||||
══════════════════════════════════════ */
|
||||
|
||||
:root {
|
||||
/* ══ 1층: 공통 테마색 ══ */
|
||||
/* 모든 블록이 공유하는 기본 팔레트 */
|
||||
|
||||
/* 텍스트 */
|
||||
--color-title: #1e293b; /* 제목 (진한 남색) */
|
||||
--color-zone-title: #1a365d; /* zone 중목차 제목 */
|
||||
--color-body: #475569; /* 본문 */
|
||||
--color-body-strong: #1e293b; /* 본문 강조 */
|
||||
--color-caption: #94a3b8; /* 캡션, 보조 */
|
||||
--color-muted: #64748b; /* 약한 텍스트 */
|
||||
|
||||
/* 배경 */
|
||||
--color-bg: #ffffff; /* 슬라이드 배경 */
|
||||
--color-bg-subtle: #f8fafc; /* 카드/영역 배경 */
|
||||
--color-bg-page: #e8ecf0; /* 페이지 배경 (슬라이드 바깥) */
|
||||
|
||||
/* 보더 */
|
||||
--color-border: #e2e8f0; /* 기본 보더 */
|
||||
--color-border-strong: #cbd5e1; /* 강한 보더 */
|
||||
|
||||
/* 강조 */
|
||||
--color-accent: #2563eb; /* 링크, 강조 (파랑) */
|
||||
--color-accent-hover: #eff6ff; /* 링크 hover 배경 */
|
||||
--color-danger: #dc2626; /* 경고, 에러 */
|
||||
|
||||
/* slide-base 전용 */
|
||||
--color-slide-title-from: #296b55; /* 대목차 gradient 시작 */
|
||||
--color-slide-title-to: #123328; /* 대목차 gradient 끝 */
|
||||
--color-footer-bg-from: #3b3523; /* footer gradient 시작 */
|
||||
--color-footer-bg-mid: #263a2a; /* footer gradient 중간 */
|
||||
--color-footer-bg-to: #113f31; /* footer gradient 끝 */
|
||||
--color-footer-text: #ffffff; /* footer 텍스트 */
|
||||
--color-footer-accent: #ffee33; /* footer 강조 (em) */
|
||||
|
||||
/* ══ 2층: 블록 의미색 ══ */
|
||||
/* 특정 블록 유형에서 의미를 가지는 색 */
|
||||
|
||||
/* 3열 비교 (prerequisites-3col) */
|
||||
--color-col-1-from: #0D78D0; /* 1열 gradient 시작 */
|
||||
--color-col-1-to: #023056; /* 1열 gradient 끝 */
|
||||
--color-col-2-from: #FF9A23; /* 2열 gradient 시작 */
|
||||
--color-col-2-to: #CC5200; /* 2열 gradient 끝 */
|
||||
--color-col-3-from: #39BE49; /* 3열 gradient 시작 */
|
||||
--color-col-3-to: #23742C; /* 3열 gradient 끝 */
|
||||
|
||||
/* 비교 블록 (compare) */
|
||||
--color-compare-left: #5c3714; /* 좌측 (AS-IS 계열) */
|
||||
--color-compare-right: #285b4a; /* 우측 (TO-BE 계열) */
|
||||
--color-compare-badge: #ae3607; /* VS 뱃지 */
|
||||
|
||||
/* 다크 카드 (direct render) */
|
||||
--color-dark-card-1: #1a365d; /* 카드 1 배경 */
|
||||
--color-dark-card-2: #1e3a2f; /* 카드 2 배경 */
|
||||
--color-dark-card-3: #3b1f2b; /* 카드 3 배경 */
|
||||
--color-dark-card-title: #fbbf24; /* 다크카드 제목 (금색) */
|
||||
--color-dark-card-body: #e2e8f0; /* 다크카드 본문 */
|
||||
|
||||
/* 표 */
|
||||
--color-table-header-bg: #64748b; /* 표 헤더 배경 */
|
||||
--color-table-header-text: #ffffff; /* 표 헤더 텍스트 */
|
||||
|
||||
/* 블록 제목 gradient (Figma 원본) */
|
||||
--color-block-title-from: #CC5200; /* 주황 gradient 시작 */
|
||||
--color-block-title-to: #883700; /* 주황 gradient 끝 */
|
||||
|
||||
/* pill */
|
||||
--color-pill-bg: #1e293b; /* pill 배경 */
|
||||
--color-pill-text: #ffffff; /* pill 텍스트 */
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/* ══════════════════════════════════════
|
||||
Spacing Tokens v1
|
||||
══════════════════════════════════════
|
||||
여백/간격/들여쓰기 공통 기준.
|
||||
══════════════════════════════════════ */
|
||||
|
||||
:root {
|
||||
/* ── 기본 스케일 ── */
|
||||
--space-xs: 4px;
|
||||
--space-sm: 8px;
|
||||
--space-md: 12px;
|
||||
--space-lg: 16px;
|
||||
--space-xl: 24px;
|
||||
|
||||
/* ── slide-base 레이아웃 ── */
|
||||
--slide-padding-x: 40px; /* 본문 좌우 여백 */
|
||||
--slide-title-left: 52px; /* 대목차 시작 */
|
||||
--slide-title-top: 22px; /* 대목차 위치 */
|
||||
--slide-divider-top: 58px; /* 구분선 위치 (slide_base.html 와 일치 2026-05-07) */
|
||||
--slide-body-top: 76px; /* 본문 시작 (사용자 직설: divider-body 16px) */
|
||||
--slide-body-height: 585px; /* 본문 높이 (사용자 직설: body-footer 10px) */
|
||||
--slide-footer-bottom: 8px; /* footer 하단 여백 (slide_base.html 와 일치) */
|
||||
--slide-footer-height: 41px; /* footer 높이 */
|
||||
|
||||
/* ── zone ── */
|
||||
--zone-gap: 8px; /* zone 간 간격 */
|
||||
--zone-padding-left: 12px; /* zone 안쪽 좌측 여백 */
|
||||
--zone-padding-right: 8px; /* zone 안쪽 우측 여백 */
|
||||
--zone-title-mb: 8px; /* zone 제목 아래 여백 */
|
||||
|
||||
/* ── 블록 공통 ── */
|
||||
--card-padding: 16px; /* 카드 내부 여백 */
|
||||
--card-padding-sm: 8px; /* 작은 카드 내부 여백 */
|
||||
--card-gap: 12px; /* 카드 간 간격 */
|
||||
--card-radius: 6px; /* 카드 모서리 */
|
||||
|
||||
/* ── 블릿/텍스트 ── */
|
||||
--bullet-indent: 14px; /* 불릿 hanging indent */
|
||||
--bullet-gap: 2px; /* 불릿 항목 간 간격 */
|
||||
--heading-gap: 4px; /* 소제목 아래 간격 */
|
||||
--section-gap: 10px; /* 섹션 간 간격 */
|
||||
|
||||
/* ── flex/grid 기본 ── */
|
||||
--flex-gap: 12px; /* 기본 flex gap */
|
||||
--flex-gap-sm: 6px; /* 좁은 flex gap */
|
||||
--grid-gap: 16px; /* 기본 grid gap */
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/* ══════════════════════════════════════
|
||||
Typography Tokens v1
|
||||
══════════════════════════════════════
|
||||
슬라이드 전체의 공통 글자 위계.
|
||||
모든 블록은 이 토큰을 참조한다.
|
||||
직접값(font-size: 11px) 금지 → var(--font-body) 사용.
|
||||
══════════════════════════════════════ */
|
||||
|
||||
:root {
|
||||
/* ── 1층: Global Hierarchy ── */
|
||||
|
||||
/* 대목차: 슬라이드 상단 제목 */
|
||||
--font-slide-title: 22px;
|
||||
--weight-slide-title: 700;
|
||||
--lh-slide-title: 1.4;
|
||||
|
||||
/* 중목차: zone 제목 */
|
||||
--font-zone-title: 16px;
|
||||
--weight-zone-title: 700;
|
||||
--lh-zone-title: 1.4;
|
||||
|
||||
/* 소목차: 블록 내 소제목, 카드 제목 */
|
||||
--font-sub-title: 12px;
|
||||
--weight-sub-title: 700;
|
||||
--lh-sub-title: 1.45;
|
||||
|
||||
/* 본문: 블릿, 설명 텍스트 */
|
||||
--font-body: 10px;
|
||||
--weight-body: 500;
|
||||
--lh-body: 1.55;
|
||||
|
||||
/* 캡션: 각주, 출처, 보조 텍스트 */
|
||||
--font-caption: 10px;
|
||||
--weight-caption: 400;
|
||||
--lh-caption: 1.4;
|
||||
|
||||
/* footer: 핵심 인사이트 pill */
|
||||
--font-footer: 20px;
|
||||
--weight-footer: 700;
|
||||
--lh-footer: 1.2;
|
||||
|
||||
/* ── 2층: Component Semantic Tokens ── */
|
||||
/* 가까운 위계에서 기본값, 필요시 override */
|
||||
|
||||
/* 본문 강조 (인라인 heading) */
|
||||
--font-body-strong: var(--font-body);
|
||||
--weight-body-strong: 600;
|
||||
|
||||
/* 자세히보기 링크 */
|
||||
--font-detail-link: var(--font-caption);
|
||||
--weight-detail-link: 500;
|
||||
|
||||
/* pill/badge 라벨 */
|
||||
--font-pill-label: var(--font-sub-title);
|
||||
--weight-pill-label: 700;
|
||||
|
||||
/* 표 헤더 */
|
||||
--font-table-header: var(--font-sub-title);
|
||||
--weight-table-header: 700;
|
||||
|
||||
/* 표 셀 */
|
||||
--font-table-cell: var(--font-body);
|
||||
--weight-table-cell: 400;
|
||||
|
||||
/* 비교 뱃지 */
|
||||
--font-compare-badge: var(--font-sub-title);
|
||||
--weight-compare-badge: 700;
|
||||
|
||||
/* 강조 인용 */
|
||||
--font-callout: var(--font-sub-title);
|
||||
--weight-callout: 700;
|
||||
|
||||
/* 상단 라벨 (overline) */
|
||||
--font-overline: var(--font-caption);
|
||||
--weight-overline: 600;
|
||||
--ls-overline: 0.05em;
|
||||
}
|
||||
Reference in New Issue
Block a user