블록 템플릿 업데이트: 수정 3개 + 신규 17개 + catalog.yaml 재정비

수정:
- compare-2col-badge, compare-detail-gradient, hero-icon-cards 개선

신규 블록:
- cards: category-strip-table, system-2col-center, hero-icon-cards_1
- emphasis: checklist-dark
- visuals: cycle-orbit
- new/: cards-3col-persona, compare-vs-rows, cycle-3way-intersect 등 8개
- redesign/: card_hero-icon-cards_1
- svg/: arc_left, arrow_conclusion, arrow_down, line_divider
- BEPs: process-product-2col SVG + 테스트

catalog.yaml 전면 재정비 (슬롯 스키마, height_cost, 카테고리 정리)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-13 10:58:09 +09:00
co-authored by Claude Opus 4.6
parent c42e01f060
commit 360cd8e44c
59 changed files with 2906 additions and 1391 deletions
File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 6.0 MiB

File diff suppressed because one or more lines are too long
@@ -1,141 +0,0 @@
<!DOCTYPE html><html><head><meta charset="UTF-8">
<style>
*{margin:0;padding:0;box-sizing:border-box;}
body{background:#e5e5e5;padding:10px;font-family:'Pretendard Variable','Noto Sans KR',sans-serif;word-break:keep-all;}
.block-pp2 {
display: flex;
gap: 0;
width: 1280px;
height: 495px;
}
.pp2-col {
flex: 1;
display: flex;
flex-direction: column;
}
.pp2-left {
background: linear-gradient(180deg, #ffffff 46%, #39311e 100%);
}
.pp2-right {
background: linear-gradient(0deg, #296b55 0%, #ffffff 56%);
}
.pp2-header-bar {
height: 47px;
margin-top: 21px;
display: flex;
align-items: center;
}
.pp2-header-bar--left {
background: linear-gradient(270deg, #a4a096 0%, #39311e 100%);
border-radius: 0 24px 24px 0;
justify-content: center;
}
.pp2-header-bar--right {
background: linear-gradient(90deg, #296b55 0%, #022017 100%);
border-radius: 24px 0 0 24px;
padding-left: 71px;
}
.pp2-header-text {
font-size: 23.3px;
font-weight: 900;
letter-spacing: 1.2px;
line-height: 33.7px;
}
.pp2-header-text--left {
color: #3e3523;
}
.pp2-header-text--right {
color: #225e4a;
}
.pp2-body {
padding: 10px 27px;
flex: 1;
}
.pp2-mid-title {
font-size: 16.6px;
font-weight: 900;
line-height: 31.6px;
margin-top: 8px;
}
.pp2-mid-title:first-child {
margin-top: 0;
}
.pp2-mid-title--left {
color: #5c3614;
}
.pp2-mid-title--right {
color: #084c56;
}
.pp2-body-text {
font-size: 13.3px;
font-weight: 700;
color: #000000;
line-height: 23.3px;
}
.pp2-compare {
display: flex;
align-items: center;
gap: 4px;
margin-bottom: 10px;
}
.pp2-compare-col {
flex: 1;
}
.pp2-compare-arrow {
flex-shrink: 0;
width: 84px;
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
color: #5c3614;
}
</style></head><body>
<div class="block-pp2">
<div class="pp2-col pp2-left">
<div class="pp2-header-bar pp2-header-bar--left">
<span class="pp2-header-text pp2-header-text--left">과정 (Process)의 혁신</span>
</div>
<div class="pp2-body">
<div class="pp2-mid-title pp2-mid-title--left">Analogue 개념 기반 업무의 Digital Transformation</div>
<div class="pp2-compare">
<div class="pp2-compare-col">
<div class="pp2-body-text">• 개념, 도서, 행정 절차 중심</div>
<div class="pp2-body-text">• 2D 도면, 전문가, 규정</div>
<div class="pp2-body-text">• 업무 구분(단절), 책임</div>
</div>
<div class="pp2-compare-arrow"></div>
<div class="pp2-compare-col">
<div class="pp2-body-text">• 시각화된 목적물, 소통, 투명성 중심</div>
<div class="pp2-body-text">• 3D 모델, 참여자, 실체</div>
<div class="pp2-body-text">• 협업(융·복합), 창의성</div>
</div>
</div>
<div class="pp2-mid-title pp2-mid-title--left">위치기반의 3D 모델을 사용하는 Process 혁신</div>
<div class="pp2-body-text">• 위치기반(지리적, 지형, 지반상태 포함)의 GIS와 3D 모델(형상, 내용속성) 기반의 건설 정보를 포함하는 BIM의 연계를 통한 업무 프로세스의 혁신</div>
<div class="pp2-mid-title pp2-mid-title--left">사용자 중심의 Solution(S/W) 제공</div>
<div class="pp2-body-text">• 인프라 건설산업의 1차적인 Process 혁신은 등고선 중심의 지형도가 아닌 속성이 포함된 수치지형도와 본태 측량에서 획득한 3D 지반모델 구축 필수</div>
<div class="pp2-body-text">• 설계와 시공에 관련된 기술을 정리하고 디지털화하여 S/W로 기술 축적</div>
<div class="pp2-body-text">• 서로 다른 S/W로 작성되어 분절화된 Analogue 방식의 성과물과 정보물을 연계가 가능하도록 설계, 시공 Solution 제공</div>
</div>
</div>
<div class="pp2-col pp2-right">
<div class="pp2-header-bar pp2-header-bar--right">
<span class="pp2-header-text pp2-header-text--right">결과 (Products)의 혁신</span>
</div>
<div class="pp2-body">
<div class="pp2-mid-title pp2-mid-title--right">Copy & Paste로 인한 하향 평준화된 기존 성과품의 품질 향상</div>
<div class="pp2-body-text">• 과거 수작업으로 시행하면서 발생하던 오류 등의 최소화</div>
<div class="pp2-body-text">• 정확한 Data에 기반한 계획과 개선된 높은 품질의 성과물</div>
<div class="pp2-mid-title pp2-mid-title--right">Analogue 기반 도서 외 Digital 기반 정보물 추가</div>
<div class="pp2-body-text">• 규정에만 의존한 도면, 수량, 계산서, 시방서 등의 성과물에 3D 모델, 시뮬레이션 등의 Digital 기반 정보물(Information Data and Products)이 추가</div>
<div class="pp2-mid-title pp2-mid-title--right">Solution을 이용한 업무효율화(사용자 편의, 협업 및 의사소통 강화 등)</div>
<div class="pp2-body-text">• 디지털 기반 성과물인 Graphic 중심의 3D 모델, 시뮬레이션을 제대로 활용하기 위해서는 기존의 낮은 수준이 아니라 공학용 사이니지(H/W) 시스템이 필수로 갖춰야만 함</div>
<div class="pp2-body-text">• Engn. Solution을 통해 프로젝트에 관한 이슈를 함께 검토하고 논의하고 다양한 건설단계별 정보를 디지털 데이터로 저장하여 건설의 전 과정을 통합관리</div>
</div>
</div>
</div>
</body></html>
@@ -0,0 +1,114 @@
<!-- 카테고리 컬러 스트립 테이블: 좌측 색상 바 + 제목/본문 × N열 × M행 -->
<!--
📋 category-strip-table
─────────────────
용도: 카테고리별 필수조건/요건을 N열로 나열. 각 열에 색상 바 + 제목 + 본문 반복.
슬롯: columns[] (각 열에 color, label, label_sub, rows[{title, body}])
Figma 원본: Page 2 / 001_개요 우측 하단 "필수조건" (기술/사람/자연 3열)
수학적 계산:
table 2123x595, scale=1200/2123=0.5652
col_w=390px, strip_w=86px, content_w=304px
title: 22px/700, body: 16px/500(#3E3523)
strip label: 24px/700 white 세로쓰기
-->
<div class="block-cst" style="--cst-count: {{ columns|length }}">
{% for col in columns %}
<div class="cst-col">
<div class="cst-strip" style="background: {{ col.color | default('#4a7fb5') }}">
{% if col.label %}<span class="cst-strip-label">{{ col.label }}</span>{% endif %}
{% if col.label_sub %}<span class="cst-strip-label">{{ col.label_sub }}</span>{% endif %}
</div>
<div class="cst-content">
{% for row in col.rows %}
{% if not loop.first %}<div class="cst-divider"></div>{% endif %}
<div class="cst-row">
<div class="cst-title">{{ row.title }}</div>
{% if row.body %}<div class="cst-body">{{ row.body }}</div>{% endif %}
</div>
{% endfor %}
</div>
</div>
{% endfor %}
</div>
<style>
/*
수학적 계산 (Figma 원본):
table 2123x595, scale = 1200/2123 = 0.5652
col: 690px → 390px, strip: 152px → 86px
title: 45px → 22px, body: 35px → 16px
N열 동적: col_w = (1200 - gap*(N-1)) / N
*/
.block-cst {
display: grid;
grid-template-columns: repeat(var(--cst-count, 3), 1fr);
gap: 4px;
width: 100%;
}
/* ── Column ── */
.cst-col {
display: flex;
border-radius: 4px;
overflow: hidden;
background: #1a1a1a;
}
/* ── Color Strip (좌측 바) ── */
.cst-strip {
width: 40px;
flex-shrink: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 8px;
padding: 12px 4px;
}
.cst-strip-label {
font-size: 20px;
font-weight: var(--weight-bold, 700);
color: #ffffff;
writing-mode: vertical-rl;
text-orientation: upright;
letter-spacing: 0.1em;
}
/* ── Content (제목 + 본문 반복) ── */
.cst-content {
flex: 1;
display: flex;
flex-direction: column;
padding: 0;
}
/* ── Row (제목 + 본문) ── */
.cst-row {
padding: 12px 14px;
display: flex;
flex-direction: column;
gap: 6px;
}
.cst-title {
font-size: 18px;
font-weight: var(--weight-bold, 700);
color: #ffffff;
line-height: 1.4;
word-break: keep-all;
}
.cst-body {
font-size: 14px;
font-weight: var(--weight-medium, 500);
color: rgba(255,255,255,0.7);
line-height: 1.6;
word-break: keep-all;
white-space: pre-line;
}
/* ── Divider (행 구분선) ── */
.cst-divider {
height: 1px;
background: rgba(255,255,255,0.15);
margin: 0 14px;
}
</style>
@@ -15,7 +15,7 @@
<div class="c2b-main">
{% if badge_title %}
<div class="c2b-ribbon">
<img src="{{ ribbon_image | default('/static/figma-assets/badge_policy.png') }}" class="c2b-ribbon-img" alt="">
<img src="{{ ribbon_image | default('svg/badge_policy.png') }}" class="c2b-ribbon-img" alt="">
<span class="c2b-ribbon-text">{{ badge_title }}</span>
</div>
{% endif %}
@@ -9,7 +9,7 @@
- 좌측 헤더: 우측 라운드 + 텍스트 우정렬 (warm 그라디언트)
- 우측 헤더: 좌측 라운드 + 텍스트 좌정렬 (teal 그라디언트)
- CSS Grid 2열×N행: 좌/우 섹션 제목이 같은 Y선에 정렬
- 번째 섹션: As-Is → 화살표 → To-Be 수평 배치 가능
- 첫 섹션 As-Is → 화살표 → To-Be 수평 배치 가능
수학적 계산:
좌/우 섹션 Y좌표 — Row1: 1166/1166(정렬), Row2: 1529/1467(62px차→Grid해결), Row3: 1845/1845(정렬)
-->
@@ -31,7 +31,7 @@
<div class="cdg-asis">
{% for b in row.left.asis %}<div class="cdg-bullet">{{ b }}</div>{% endfor %}
</div>
<img src="{{ arrow_image | default('../../../static/figma-assets/arrow_asis_tobe.png') }}" class="cdg-arrow" alt="→">
<img src="{{ arrow_image | default('svg/arrow_asis_tobe.png') }}" class="cdg-arrow" alt="→">
<div class="cdg-tobe">
{% for b in row.left.tobe %}<div class="cdg-bullet">{{ b }}</div>{% endfor %}
</div>
@@ -64,16 +64,27 @@
행 공유 → 좌/우 섹션 제목이 같은 Y선에 자동 정렬
Figma Row2 차이: 좌 y=1529, 우 y=1467 (62px) → Grid가 해결
*/
/*
B안: Grid 배경에 좌/우 절반씩 연속 그라디언트
→ 셀 경계가 안 보이고 Figma처럼 자연스러운 배경
→ Grid 행 공유로 Y선 정렬도 유지
*/
.block-cdg {
display: grid;
grid-template-columns: 1fr 1fr;
width: 100%;
overflow: hidden;
background: linear-gradient(90deg,
rgba(255,255,255,0.4) 0%,
rgba(57,50,30,0.12) 50%,
rgba(41,107,85,0.06) 50%,
rgba(255,255,255,0.4) 100%
);
}
/* ── Headers (비대칭 라운드) ── */
.cdg-header { padding: 8px 20px; display: flex; min-height: 36px; align-items: center; }
.cdg-header-text { font-size: 15px; font-weight: var(--weight-black, 900); color: #000; line-height: 1.3; }
/* ── Headers (비대칭 라운드 — 자체 배경 유지) ── */
.cdg-header { padding: 12px 28px; display: flex; min-height: 52px; align-items: center; }
.cdg-header-text { font-size: 26px; font-weight: var(--weight-black, 900); color: #000; line-height: 1.3; }
.cdg-header-warm {
background: linear-gradient(90deg, rgba(165,161,150,0.15), rgba(57,50,30,0.85));
border-radius: 0 28px 28px 0; justify-content: flex-end; text-align: right; margin-right: 4px;
@@ -83,17 +94,18 @@
border-radius: 28px 0 0 28px; justify-content: flex-start; text-align: left; margin-left: 4px;
}
/* ── Grid Cells (행 공유 → 좌우 Y선 정렬) ── */
/* ── Grid Cells (배경 제거 → Grid 배경이 투과) ── */
.cdg-cell {
padding: 8px 14px;
display: flex; flex-direction: column; gap: 4px;
padding: 14px 20px;
display: flex; flex-direction: column; gap: 6px;
align-self: start;
background: none;
}
.cdg-cell-warm { background: linear-gradient(180deg, rgba(255,255,255,0.4), rgba(57,50,30,0.08)); }
.cdg-cell-teal { background: linear-gradient(180deg, rgba(41,107,85,0.06), rgba(255,255,255,0.4)); }
.cdg-cell-warm { background: none; }
.cdg-cell-teal { background: none; }
/* ── Section Title & Body ── */
.cdg-sec-title { font-size: 12px; font-weight: var(--weight-black, 900); line-height: 1.4; word-break: keep-all; margin-bottom: 2px; }
.cdg-sec-title { font-size: 18px; font-weight: var(--weight-black, 900); line-height: 1.4; word-break: keep-all; margin-bottom: 4px; }
.cdg-title-warm { color: var(--color-warm-brown, #5C3714); }
.cdg-title-teal { color: var(--color-dark-teal, #084C56); }
.cdg-sec-body { padding-left: 8px; }
@@ -101,7 +113,7 @@
/* ── Bullets ── */
.cdg-bullet {
position: relative; padding-left: 14px;
font-size: 11px; font-weight: var(--weight-bold, 700); color: #1a1a1a;
font-size: 14px; font-weight: var(--weight-bold, 700); color: #1a1a1a;
line-height: 1.7; word-break: keep-all;
}
.cdg-bullet::before { content: '•'; position: absolute; left: 0; color: #666; }
+3 -3
View File
@@ -19,7 +19,7 @@
<div class="hic-card-area">
{% if badge_title %}
<div class="hic-ribbon">
<img src="{{ ribbon_image | default('/static/figma-assets/badge_solution.png') }}" class="hic-ribbon-img" alt="">
<img src="{{ ribbon_image | default('svg/badge_solution.png') }}" class="hic-ribbon-img" alt="">
<span class="hic-ribbon-text">{{ badge_title }}</span>
</div>
{% endif %}
@@ -42,14 +42,14 @@
<style>
.block-hic {
display: flex; flex-direction: column; align-items: center;
width: 100%; background: #0a0a0a; border-radius: 16px;
width: 100%; border-radius: 16px;
padding: 36px 32px 28px; overflow: visible;
}
/* ── Hero Statement ── */
.hic-statement {
text-align: center; font-size: 28px; font-weight: var(--weight-bold, 700);
color: #fff; line-height: 1.6; word-break: keep-all;
color: #1a1a1a; line-height: 1.6; word-break: keep-all;
margin-bottom: 28px; padding: 0 24px;
}
.hic-statement strong { font-weight: 900; font-size: 1.1em; }
@@ -0,0 +1,176 @@
<!-- 중앙 라벨 2열 시스템 구성: 좌(H/W) / 중앙 원형 라벨 / 우(S/W) -->
<!--
📋 system-2col-center
─────────────────
용도: 시스템 구성요소를 좌/우 카테고리로 나열. 중앙에 원형 라벨.
슬롯: center_title, center_sub, left_label, right_label, left_items[], right_items[]
Figma 원본: Page 3 / f8 (System 구성 BIG Room, 2446x1943)
수학적 계산:
scale = 1200/2446 = 0.4906
H/W 영역: 561px, S/W 영역: 549px
중앙 원: 329px → 실사용 120px
tab: 164x43px, tab font: 22px
item font: 15px, item title: 16px bold
-->
<div class="block-s2c">
<!-- 좌측 헤더 탭 -->
<div class="s2c-tab s2c-tab-left" style="background: {{ left_color | default('#838486') }}">
{{ left_label }}
</div>
<!-- 우측 헤더 탭 -->
<div class="s2c-tab s2c-tab-right" style="background: {{ right_color | default('#d16013') }}">
{{ right_label }}
</div>
<!-- 좌측 항목 -->
<div class="s2c-col s2c-left">
{% for item in left_items %}
<div class="s2c-item">
{% if item.icon %}<span class="s2c-icon">{{ item.icon }}</span>{% endif %}
<div class="s2c-item-content">
<div class="s2c-item-title">{{ item.title }}</div>
{% if item.body %}<div class="s2c-item-body">{{ item.body }}</div>{% endif %}
</div>
</div>
{% endfor %}
</div>
<!-- 중앙 원형 라벨 -->
<div class="s2c-center">
<div class="s2c-circle">
<div class="s2c-center-title">{{ center_title }}</div>
{% if center_sub %}<div class="s2c-center-sub">{{ center_sub }}</div>{% endif %}
</div>
</div>
<!-- 우측 항목 -->
<div class="s2c-col s2c-right">
{% for item in right_items %}
<div class="s2c-item">
{% if item.icon %}<span class="s2c-icon">{{ item.icon }}</span>{% endif %}
<div class="s2c-item-content">
<div class="s2c-item-title">{{ item.title }}</div>
{% if item.body %}<div class="s2c-item-body">{{ item.body }}</div>{% endif %}
</div>
</div>
{% endfor %}
</div>
</div>
<style>
/*
수학적 계산 (Figma 원본):
frame 2446x1943, scale = 1200/2446 = 0.4906
H/W: 1144 → 561px, S/W: 1119 → 549px
center circle: 671 → 329px → 실사용 120px
tab: 335x88 → 164x43px
*/
.block-s2c {
display: grid;
grid-template-columns: 1fr auto 1fr;
grid-template-rows: auto 1fr;
width: 100%;
gap: 0;
}
/* ── Header Tabs ── */
.s2c-tab {
padding: 8px 20px;
font-size: 20px;
font-weight: var(--weight-bold, 700);
color: #ffffff;
border-radius: 6px;
}
.s2c-tab-left {
grid-column: 1;
grid-row: 1;
justify-self: start;
}
.s2c-tab-right {
grid-column: 3;
grid-row: 1;
justify-self: end;
}
/* ── Columns ── */
.s2c-col {
display: flex;
flex-direction: column;
gap: 16px;
padding: 16px 12px;
}
.s2c-left {
grid-column: 1;
grid-row: 2;
}
.s2c-right {
grid-column: 3;
grid-row: 2;
}
/* ── Center Circle ── */
.s2c-center {
grid-column: 2;
grid-row: 1 / 3;
display: flex;
align-items: center;
justify-content: center;
padding: 0 20px;
}
.s2c-circle {
width: 120px;
height: 120px;
border-radius: 50%;
background: linear-gradient(135deg, #2a8a8a, #1a6060);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
flex-shrink: 0;
}
.s2c-center-title {
font-size: 18px;
font-weight: var(--weight-black, 900);
color: #ffffff;
line-height: 1.3;
}
.s2c-center-sub {
font-size: 13px;
font-weight: var(--weight-medium, 500);
color: rgba(255,255,255,0.7);
line-height: 1.3;
}
/* ── Items ── */
.s2c-item {
display: flex;
gap: 10px;
align-items: flex-start;
}
.s2c-icon {
font-size: 20px;
flex-shrink: 0;
line-height: 1.4;
}
.s2c-item-content {
display: flex;
flex-direction: column;
gap: 3px;
}
.s2c-item-title {
font-size: 16px;
font-weight: var(--weight-bold, 700);
color: var(--color-primary, #1e293b);
line-height: 1.4;
word-break: keep-all;
}
.s2c-item-body {
font-size: 14px;
font-weight: var(--weight-medium, 500);
color: var(--color-text-secondary, #64748b);
line-height: 1.6;
word-break: keep-all;
white-space: pre-line;
}
</style>
@@ -1,149 +0,0 @@
<!DOCTYPE html><html><head><meta charset="UTF-8">
<style>
*{margin:0;padding:0;box-sizing:border-box;}
body{background:#f0f0f0;padding:20px;font-family:'Pretendard Variable','Noto Sans KR',sans-serif;word-break:keep-all;}
</style></head><body>
<div style="width:1280px;background:#fff;padding:40px;">
<!-- 그라디언트 상세 2열 비교: 비대칭 라운드 헤더 + 행 공유 + As-Is/To-Be -->
<!--
📋 compare-detail-gradient
─────────────────
용도: 두 카테고리의 상세 비교 (각각 N개 하위 섹션, 행 공유 정렬)
슬롯: left_header, right_header, sections[] (각 row에 left + right)
Figma 원본: Frame 4 (과정의 혁신 vs 결과의 혁신)
디자인:
- 좌측 헤더: 우측 라운드 + 텍스트 우정렬 (warm 그라디언트)
- 우측 헤더: 좌측 라운드 + 텍스트 좌정렬 (teal 그라디언트)
- CSS Grid 2열×N행: 좌/우 섹션 제목이 같은 Y선에 정렬
- 첫 번째 섹션: As-Is → 화살표 → To-Be 수평 배치 가능
수학적 계산:
좌/우 섹션 Y좌표 — Row1: 1166/1166(정렬), Row2: 1529/1467(62px차→Grid해결), Row3: 1845/1845(정렬)
-->
<div class="block-cdg">
<!-- Row 0: Headers -->
<div class="cdg-header cdg-header-warm">
<span class="cdg-header-text">과정 (Process)의 혁신</span>
</div>
<div class="cdg-header cdg-header-teal">
<span class="cdg-header-text">결과 (Products)의 변화</span>
</div>
<!-- Rows: sections (행 공유로 좌/우 Y선 자동 정렬) -->
<div class="cdg-cell cdg-cell-warm">
<div class="cdg-sec-title cdg-title-warm">Analogue 기반 업무의 Digital Transformation</div>
<div class="cdg-asis-tobe">
<div class="cdg-asis">
<div class="cdg-bullet">개념·문서·행정 절차 중심</div><div class="cdg-bullet">2D 도면, 전문가, 규정</div><div class="cdg-bullet">업무 구분(단절), 책임</div>
</div>
<img src="/static/figma-assets/arrow_asis_tobe.png" class="cdg-arrow" alt="→">
<div class="cdg-tobe">
<div class="cdg-bullet">시각화된 목적물, 소통, 투명성 중심</div><div class="cdg-bullet">3D 모델, 참여자, 실체</div><div class="cdg-bullet">협업(융·복합), 창의성</div>
</div>
</div>
</div>
<div class="cdg-cell cdg-cell-teal">
<div class="cdg-sec-title cdg-title-teal">Copy & Paste로 인한 하향 평준화된 기존 성과물의 품질 향상</div>
<div class="cdg-sec-body">
<div class="cdg-bullet">과거 수작업으로 시행하면서 발생하던 오류 등의 최소화</div><div class="cdg-bullet">정확한 Data에 기반한 계획으로 고품질 성과물 도출</div>
</div>
</div>
<div class="cdg-cell cdg-cell-warm">
<div class="cdg-sec-title cdg-title-warm">위치기반의 3D 모델을 사용하는 Process 혁신</div>
<div class="cdg-sec-body">
<div class="cdg-bullet">지리·지형·지반 등 위치정보(GIS)와 3D모델(형상, 속성정보) 기반의 건설 정보를 포함하는 BIM의 연계를 통한 업무 프로세스의 혁신</div>
</div>
</div>
<div class="cdg-cell cdg-cell-teal">
<div class="cdg-sec-title cdg-title-teal">Analogue 기반 도서 외 Digital 기반 정보물 추가</div>
<div class="cdg-sec-body">
<div class="cdg-bullet">기존 성과물(도면, 수량, 계산서, 시방서 등)에 3D 모델, Simulation 등의 Digital 기반 정보물 추가</div>
</div>
</div>
<div class="cdg-cell cdg-cell-warm">
<div class="cdg-sec-title cdg-title-warm">사용자 중심의 Solution(S/W) 제공</div>
<div class="cdg-sec-body">
<div class="cdg-bullet">서로 다른 S/W로 작성되어 분절화된 Analogue 방식의 성과물과 정보물을 연계할 수 있는 설계·시공 Solution 제공</div>
</div>
</div>
<div class="cdg-cell cdg-cell-teal">
<div class="cdg-sec-title cdg-title-teal">Solution을 활용한 업무 효율화</div>
<div class="cdg-sec-body">
<div class="cdg-bullet">Engn. Solution을 통해 성과물에 관한 이슈를 함께 검토·논의하는 협업 환경 조성</div><div class="cdg-bullet">건설 단계별 정보를 디지털 데이터로 축적하여, 건설 전 과정을 통합관리</div>
</div>
</div>
</div>
<style>
/*
CSS Grid: 2열 × (1+N)행
행 공유 → 좌/우 섹션 제목이 같은 Y선에 자동 정렬
Figma Row2 차이: 좌 y=1529, 우 y=1467 (62px) → Grid가 해결
*/
.block-cdg {
display: grid;
grid-template-columns: 1fr 1fr;
width: 100%;
overflow: hidden;
}
/* ── Headers (비대칭 라운드) ── */
.cdg-header { padding: 12px 28px; display: flex; min-height: 52px; align-items: center; }
.cdg-header-text { font-size: 23.3px; font-weight: var(--weight-black, 900); color: #000; line-height: 1.3; }
.cdg-header-warm {
background: linear-gradient(90deg, rgba(165,161,150,0.15), rgba(57,50,30,0.85));
border-radius: 0 28px 28px 0; justify-content: flex-end; text-align: right; margin-right: 4px;
}
.cdg-header-teal {
background: linear-gradient(90deg, rgba(3,33,24,0.85), rgba(41,107,85,0.15));
border-radius: 28px 0 0 28px; justify-content: flex-start; text-align: left; margin-left: 4px;
}
/* ── Grid Cells (행 공유 → 좌우 Y선 정렬) ── */
.cdg-cell {
padding: 14px 20px;
display: flex; flex-direction: column; gap: 6px;
align-self: start;
}
.cdg-cell-warm { background: linear-gradient(180deg, rgba(255,255,255,0.4), rgba(57,50,30,0.08)); }
.cdg-cell-teal { background: linear-gradient(180deg, rgba(41,107,85,0.06), rgba(255,255,255,0.4)); }
/* ── Section Title & Body ── */
.cdg-sec-title { font-size: 16.6px; font-weight: var(--weight-black, 900); line-height: 1.4; word-break: keep-all; margin-bottom: 4px; }
.cdg-title-warm { color: var(--color-warm-brown, #5C3714); }
.cdg-title-teal { color: var(--color-dark-teal, #084C56); }
.cdg-sec-body { padding-left: 8px; }
/* ── Bullets ── */
.cdg-bullet {
position: relative; padding-left: 14px;
font-size: 13.3px; font-weight: var(--weight-bold, 700); color: #1a1a1a;
line-height: 23.3px; word-break: keep-all;
}
.cdg-bullet::before { content: '•'; position: absolute; left: 0; color: #666; }
/* ── As-Is → To-Be 수평 레이아웃 ── */
.cdg-asis-tobe { display: flex; align-items: center; gap: 8px; margin-top: 4px; }
.cdg-asis, .cdg-tobe { flex: 1; padding-left: 8px; }
.cdg-arrow { width: 60px; height: auto; flex-shrink: 0; opacity: 0.7; }
</style>
</div>
</body></html>
@@ -1,162 +0,0 @@
<!DOCTYPE html><html><head><meta charset="UTF-8">
<style>
*{margin:0;padding:0;box-sizing:border-box;}
body{background:#f0f0f0;padding:20px;font-family:'Pretendard Variable','Noto Sans KR',sans-serif;word-break:keep-all;}
</style></head><body>
<div style="width:1280px;background:#fff;padding:40px;">
<!-- 히어로 카드 변형1: 3D 리본 배지 + N열 카드 (제목+중제목+불릿 계층) -->
<!--
📋 hero-icon-cards_1
─────────────────
용도: 핵심 요건/목표를 N열 카드로 시각화. 각 카드에 제목+중제목+불릿 계층.
슬롯: statement(선택), badge_title, cards[] (title, sections[{title, bullets[]}])
변형 원본: hero-icon-cards
변경점: icon/title/subtitle → sections[{title, bullets[]}] 계층으로 변경
수학적 계산: hero-icon-cards와 동일
badge 508x94 at y=1431, box at y=1449, frame_w=1808
scale = 1200/1808 = 0.6637
ribbon: 337x62px, fold_offset: 12px, ribbon_below_fold: 50px
box padding-top: 56px
-->
<div class="block-hic">
<div class="hic-card-area">
<div class="hic-ribbon">
<img src="../../../static/figma-assets/badge_solution.png" class="hic-ribbon-img" alt="">
<span class="hic-ribbon-text">DX 시행을 위한 필수 요건</span>
</div>
<div class="hic-box">
<div class="hic-cards">
<div class="hic-card">
<div class="hic-title">기술(디지털)</div>
<div class="hic-sec-title">Digital 기술(S/W, H/W)과 업무 Process의 통합</div>
<div class="hic-bullet">기존 업무 프로세스에 다양한 디지털 기술을 접목하여 업무 수행</div>
<div class="hic-bullet">프로젝트 전반에 걸친 업무 프로세스의 연결 및 조율</div>
<div class="hic-sec-title">분야별 전문 지식(설계, 시공, 유지관리 등) 보유</div>
<div class="hic-bullet">건설 전 단계에 대한 근본적인 이해와 지식 및 경험</div>
<div class="hic-bullet">최신 토목 기술 트랜드 및 표준 기준 등에 대한 높은 지식</div>
</div>
<div class="hic-sep"></div>
<div class="hic-card">
<div class="hic-title">사람(역량)</div>
<div class="hic-sec-title">혁신적 사고방식과 창의적 문제 해결 능력</div>
<div class="hic-bullet">기존 수행 방식과 관습적 사고 등에 의한 접근 방식 탈피</div>
<div class="hic-bullet">디지털 기술을 활용한 창의적, 혁신적인 솔루션 제시</div>
<div class="hic-sec-title">사용자 중심 사고와 DX 수행 경험</div>
<div class="hic-bullet">사용자의 요구와 기대를 충족시키는 설계 및 구현</div>
<div class="hic-bullet">시행착오를 포함한 수행 경험과 사용자 경험(UX)을 반영한 해결 방안 제시</div>
</div>
<div class="hic-sep"></div>
<div class="hic-card">
<div class="hic-title">자연(여건)</div>
<div class="hic-sec-title">지속적인 투자 및 실행 의지</div>
<div class="hic-bullet">기술 도입 초기 단계에 필요한 인력·기간·비용 등의 대규모 투자</div>
<div class="hic-bullet">기술 고도화를 위한 지속적인 개선 및 투자 체계 구축</div>
<div class="hic-bullet">변화와 혁신을 통해 부가가치를 창출하려는 실행 의지와 추진력</div>
</div>
</div>
</div>
</div>
</div>
<style>
.block-hic {
display: flex; flex-direction: column; align-items: center;
width: 100%; border-radius: 16px;
padding: 36px 32px 28px; overflow: visible;
}
/* ── Hero Statement ── */
.hic-statement {
text-align: center; font-size: 28px; font-weight: var(--weight-bold, 700);
color: #fff; line-height: 1.6; word-break: keep-all;
margin-bottom: 28px; padding: 0 24px;
}
.hic-statement strong { font-weight: 900; font-size: 1.1em; }
.hic-statement em { color: #ef4444; font-style: normal; font-weight: 900; font-size: 1.15em; }
/*
리본+박스 수학적 계산 (Figma 원본):
badge 508x94 at y=1431, box at y=1449
접힘선 = 18px = 이미지 높이의 19.1%
scale(1200/1808) → ribbon 337x62, fold top에서 12px, 아래 50px
*/
.hic-card-area { position: relative; width: 100%; margin-top: 20px; }
.hic-ribbon {
position: absolute;
top: -12px; /* 접힘선이 박스 top border와 정확히 일치 */
left: 50%; transform: translateX(-50%);
z-index: 2; width: 337px; text-align: center;
}
.hic-ribbon-img { width: 100%; height: auto; display: block; }
.hic-ribbon-text {
position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
font-size: 20px; font-weight: 700; color: #fff;
letter-spacing: 0.03em; white-space: nowrap;
text-shadow: 0 1px 3px rgba(0,0,0,0.3);
}
/* 빨간 테두리 흰 박스 */
.hic-box {
position: relative; background: #fff;
border: 6px solid #9b1b1b; border-radius: 20px;
padding: 56px 8px 8px; /* top: ribbon_below(50) + 6px 여유 */
}
.hic-cards { display: flex; align-items: stretch; width: 100%; }
.hic-card {
flex: 1; display: flex; flex-direction: column;
padding: 16px 12px 20px; gap: 0;
}
.hic-sep { width: 1px; background: #e0e0e0; align-self: stretch; margin: 8px 0; }
/* ── 카드 내부 (변형: icon → 소제목+불릿 계층) ── */
/* 중제목 (카드 헤더: 기술/사람/자연): 중앙 정렬 */
.hic-title { font-size: 20px; font-weight: var(--weight-black, 900); color: #1a1a1a; line-height: 1.3; text-align: center; margin-bottom: 12px; }
/* 소제목 (D1): 16.6px/900, 들여쓰기 1단 = 16px */
.hic-sec-title { font-size: 16.6px; font-weight: 900; color: #1a1a1a; line-height: 1.4; margin-top: 8px; margin-bottom: 3px; padding-left: 16px; }
.hic-sec-title:first-of-type { margin-top: 0; }
/* 불릿 (D2): 13.3px/700, 들여쓰기 2단 = 36px, lineH=23.3px */
.hic-bullet {
position: relative; padding-left: 36px;
font-size: 13.3px; font-weight: 700; color: #334155;
line-height: 23.3px; word-break: keep-all;
}
.hic-bullet::before { content: '•'; position: absolute; left: 24px; color: #666; }
</style>
</div>
</body></html>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 204 KiB

@@ -0,0 +1,74 @@
<!-- 체크리스트 다크: 체크 아이콘 + 제목:설명 N행, 다크 배경 -->
<!--
📋 checklist-dark
─────────────────
용도: 핵심 요건/원칙을 체크박스 스타일로 나열. 제목:설명 구조.
슬롯: items[] (각 항목에 title, description)
Figma 원본: Page 3 / f5 (개발 패러다임 체크리스트, 1770x553)
수학적 계산:
scale = 1200/1770 = 0.6780
icon: 31x24px, 행 간격: 64px
font: 42px → 16px
-->
<div class="block-cld">
{% for item in items %}
<div class="cld-row">
<div class="cld-check"></div>
<div class="cld-text">
<span class="cld-title">{{ item.title }}</span>
{% if item.description %}<span class="cld-sep"> : </span><span class="cld-desc">{{ item.description }}</span>{% endif %}
</div>
</div>
{% endfor %}
</div>
<style>
/*
수학적 계산 (Figma 원본):
frame 1770x553, scale = 1200/1770 = 0.6780
icon 45x36 → 31x24, row gap 94 → 64px
font 42px → 16px
*/
.block-cld {
display: flex;
flex-direction: column;
gap: 8px;
width: 100%;
background: #1a1a1a;
border-radius: 10px;
padding: 20px 24px;
}
.cld-row {
display: flex;
align-items: flex-start;
gap: 12px;
}
/* ── Check Icon ── */
.cld-check {
font-size: 18px;
color: #d4722a;
flex-shrink: 0;
line-height: 1.6;
}
/* ── Text (title : description) ── */
.cld-text {
font-size: 16px;
line-height: 1.6;
color: #ffffff;
word-break: keep-all;
}
.cld-title {
font-weight: var(--weight-bold, 700);
color: #ffffff;
}
.cld-sep {
color: rgba(255,255,255,0.5);
}
.cld-desc {
font-weight: var(--weight-medium, 500);
color: rgba(255,255,255,0.8);
}
</style>
@@ -0,0 +1,117 @@
<!-- 3열 페르소나 카드: CSS overlay + 이미지(bg, badge, icon, photo) -->
<!--
📋 cards-3col-persona
─────────────────
용도: 3개 역할/관점별 목표를 나란히 비교. 뱃지+불릿+사진 3단 구성.
슬롯:
personas[3]:
bg_img — 컬럼 배경 텍스처 (이미지, 실사)
overlay_color — 오버레이 색상 (CSS, 기본값 제공)
badge_outer_img, badge_inner_img — 원형 뱃지 (이미지, 일러스트)
label_line1, label_line2, label_color
bullet_icon — 체크 아이콘 (이미지)
bullets[] (text, compact: bool)
photo_img — 하단 사진 (이미지, 실사)
Figma 원본: Frame 1171281191 (node 45:16, 2601×1927)
수학적 계산:
scale = 1280 / 2601 = 0.49213
badge: 396×397 → 195×195, inner offset (12%,14%), size 76%
overlay: 단색 opacity 0.8, radius ~30px (MCP opacity-80 확인)
left=#d6e7c4, mid=#e1efe1, right=#d0c0ad (픽셀 분석)
label: 65px/50px Bold (MCP 확인)
bullet icon: 32.4×32.5 → 16×16 (이미지, 아이콘)
bullet text: 40px/85px Medium #000 (MCP 확인)
photo: radius=50px→25px, opacity=0.7 (MCP opacity-70 확인)
CSS 요소: overlay 단색+opacity+radius
이미지 요소: bg(텍스처), badge(일러스트), icon(아이콘), photo(실사)
인사이트: I-2(컬럼 동일 top/bottom, space-between), R13(marker+text flex pair)
-->
<div class="block-c3p">
{% for p in personas %}
<div class="c3p-col">
{% if p.bg_img %}<img src="{{ p.bg_img }}" class="c3p-bg" alt="">{% endif %}
<div class="c3p-overlay" style="background: {{ p.overlay_color|default('#d6e7c4') }};"></div>
<div class="c3p-badge">
{% if p.badge_outer_img %}<img src="{{ p.badge_outer_img }}" class="c3p-badge-outer" alt="">{% endif %}
{% if p.badge_inner_img %}<img src="{{ p.badge_inner_img }}" class="c3p-badge-inner" alt="">{% endif %}
<div class="c3p-badge-label" style="color: {{ p.label_color|default('#285b4a') }};">
{% if p.label_line1 %}<span class="c3p-ln1">{{ p.label_line1 }}</span>{% endif %}
{% if p.label_line2 %}<span class="c3p-ln2">{{ p.label_line2 }}</span>{% endif %}
</div>
</div>
<div class="c3p-bullets">
{% for b in p.bullets %}
<div class="c3p-bullet {{ 'c3p-bullet--compact' if b.compact }}">
{% if p.bullet_icon %}<span class="c3p-bullet-icon"><img src="{{ p.bullet_icon }}" alt=""></span>{% endif %}
<span class="c3p-bullet-text">{{ b.text|safe }}</span>
</div>
{% endfor %}
</div>
{% if p.photo_img %}
<div class="c3p-photo"><img src="{{ p.photo_img }}" alt=""></div>
{% endif %}
</div>
{% endfor %}
</div>
<style>
.block-c3p {
display: flex; gap: 4px;
width: 100%; height: 100%; word-break: keep-all;
}
.c3p-col {
flex: 1; position: relative;
display: flex; flex-direction: column; align-items: center;
overflow: hidden;
}
.c3p-bg {
position: absolute; inset: 0;
width: 100%; height: 100%; object-fit: cover; z-index: 0;
}
/* overlay: CSS 단색 (MCP opacity-80, 픽셀 분석 색상) */
.c3p-overlay {
position: absolute; top: 10%; left: 5%;
width: 90%; height: 70%;
opacity: 0.8; border-radius: 30px; z-index: 1;
}
.c3p-badge {
position: relative; z-index: 2;
width: 120px; height: 120px; flex: none; margin-bottom: 8px;
}
.c3p-badge-outer { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; }
.c3p-badge-inner { position: absolute; left: 12%; top: 14%; width: 76%; height: 76%; object-fit: contain; }
.c3p-badge-label {
position: absolute; inset: 0;
display: flex; flex-direction: column; align-items: center; justify-content: center;
font-weight: 700; text-align: center; letter-spacing: -0.02em; z-index: 3;
}
.c3p-ln1 { font-size: 20px; line-height: 1.1; }
.c3p-ln2 { font-size: 16px; line-height: 1.2; }
/* bullets: I-2 space-between, R13 flex pair */
.c3p-bullets {
position: relative; z-index: 2;
flex: 1; display: flex; flex-direction: column;
justify-content: space-between; width: 90%; padding: 4px 0;
}
.c3p-bullet { display: flex; align-items: flex-start; }
.c3p-bullet--compact .c3p-bullet-text { line-height: 1.3; }
.c3p-bullet-icon { flex: none; width: 16px; height: 16px; margin-top: 0.35em; margin-right: 6px; }
.c3p-bullet-icon img { width: 100%; height: 100%; object-fit: contain; }
.c3p-bullet-text { flex: 1; font-size: 15px; font-weight: 500; color: #000; line-height: 1.6; }
/* photo: MCP opacity-70, radius=50px→25px */
.c3p-photo {
position: relative; z-index: 2;
width: 95%; border-radius: 16px;
overflow: hidden; opacity: 0.7; margin-top: auto;
}
.c3p-photo img { width: 100%; aspect-ratio: 1/1; object-fit: cover; display: block; }
</style>
+122
View File
@@ -0,0 +1,122 @@
<!-- VS 비교 행: CSS gradient pills + 좌/우 텍스트 비교 -->
<!--
📋 compare-vs-rows
─────────────────
용도: A vs B를 카테고리별로 좌/우 비교. CSS gradient pill, 하단 결론 박스.
슬롯:
header (icon, title) — 선택
main_labels (left, center, right)
rows[] (category, left_text, right_text)
conclusion (arrow_img, text — HTML with <em>)
Figma 원본: Frame 1171281195 (node 45:20, 1868×1908)
수학적 계산:
scale = 1280 / 1868 = 0.685225
main pill: 1803×75, radius=50px, grid 748|242|813
cat pill: 242px, radius=10px
left: #5c3714 Bold, right: #285b4a Bold (MCP 확인)
conclusion: SVG 분석 bg=#FAEDCB mix-blend-mode:multiply
CSS 요소: main pill gradient, cat pill gradient, conclusion bg, header gradient text
이미지 요소: header icon, conclusion arrow
-->
<div class="block-cvr">
{% if header %}
<div class="cvr-header">
{% if header.icon %}<div class="cvr-header-icon"><img src="{{ header.icon | default('svg/icon_header.png') }}" alt=""></div>{% endif %}
<div class="cvr-header-title">{{ header.title }}</div>
</div>
{% endif %}
{% if main_labels %}
<div class="cvr-main-pill">
<div>{{ main_labels.left }}</div>
<div>{{ main_labels.center|default('vs.') }}</div>
<div>{{ main_labels.right }}</div>
</div>
{% endif %}
<div class="cvr-rows">
{% for row in rows %}
<div class="cvr-row">
<div class="cvr-left">{{ row.left_text|safe }}</div>
<div class="cvr-cat">{{ row.category }}</div>
<div class="cvr-right">{{ row.right_text|safe }}</div>
</div>
{% endfor %}
</div>
{% if conclusion %}
<div class="cvr-conclusion">
{% if conclusion.arrow_img %}<img src="{{ conclusion.arrow_img | default('svg/arrow_conclusion.svg') }}" class="cvr-conclusion-arrow" alt="">{% endif %}
<div class="cvr-conclusion-bg"></div>
<div class="cvr-conclusion-text">{{ conclusion.text|safe }}</div>
</div>
{% endif %}
</div>
<style>
.block-cvr {
display: flex; flex-direction: column;
width: 100%; word-break: keep-all;
}
.cvr-header { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
.cvr-header-icon { width: 24px; height: 24px; flex: none; }
.cvr-header-icon img { width: 100%; height: 100%; object-fit: contain; }
.cvr-header-title {
font-weight: 700; font-size: 28px;
background-image: linear-gradient(180deg, #cc5200 0%, #883700 100%);
-webkit-background-clip: text; background-clip: text; color: transparent;
text-shadow: 0 0 4px #322c1e;
}
/* main pill: CSS gradient (MCP 확인) */
.cvr-main-pill {
display: grid; grid-template-columns: 40fr 13fr 47fr;
align-items: center; height: 36px; border-radius: 24px;
background: linear-gradient(270deg, #285b4a 0%, rgba(40,91,74,0.8) 30%, rgba(74,64,38,0.8) 70%, #4a4026 100%);
margin-bottom: 4px;
}
.cvr-main-pill > div { font-weight: 700; font-size: 22px; color: #fff; text-align: center; white-space: nowrap; }
.cvr-rows { display: flex; flex-direction: column; flex: 1; }
.cvr-row {
display: grid; grid-template-columns: 40fr 13fr 47fr;
align-items: center; min-height: 36px;
border-bottom: 1px solid rgba(0,0,0,0.06);
}
.cvr-left {
font-weight: 700; font-size: 16px; color: #5c3714;
text-align: right; padding: 6px 12px; line-height: 1.3;
}
.cvr-right {
font-weight: 700; font-size: 16px; color: #285b4a;
text-align: left; padding: 6px 12px; line-height: 1.3;
}
.cvr-left .sub, .cvr-right .sub { font-size: 14px; }
/* cat pill: CSS gradient */
.cvr-cat {
font-weight: 700; font-size: 16px; color: #fff;
text-align: center; white-space: nowrap; padding: 6px 8px; border-radius: 6px;
background: linear-gradient(270deg, rgba(40,91,74,0.8) 0%, rgba(40,91,74,0.64) 30%, rgba(74,64,38,0.64) 70%, rgba(74,64,38,0.8) 100%);
}
/* conclusion: CSS bg (SVG 분석 #FAEDCB + multiply) */
.cvr-conclusion {
position: relative; display: flex; align-items: center;
gap: 12px; margin-top: 8px; padding: 8px 16px; min-height: 60px;
}
.cvr-conclusion-arrow {
flex: none; width: 80px; height: 60px;
object-fit: contain; transform: rotate(180deg);
}
.cvr-conclusion-bg {
position: absolute; inset: 0;
background: #FAEDCB; mix-blend-mode: multiply; z-index: 0;
}
.cvr-conclusion-text {
position: relative; z-index: 1;
font-weight: 700; font-size: 18px; color: #000; line-height: 1.5;
}
.cvr-conclusion-text em { font-style: normal; color: #ae3607; font-size: 20px; }
</style>
@@ -0,0 +1,162 @@
<!-- 3원 교차 다이어그램: CSS circles/gradient + 이미지(arc, texture) -->
<!--
📋 cycle-3way-intersect
─────────────────
용도: 3가지 목표/가치가 서로 교차하는 벤 다이어그램
슬롯:
bg_texture_img — 하단 배경 텍스처 (이미지, 실사)
arc_img — 연결 아크 (이미지, 곡선 CSS 불가)
circles[3]:
label (HTML), text_shadow
outer_gradient, ring_gradient — CSS gradient (gradient_math.py 계산값)
accents[6]:
char (한자 1글자)
outer_gradient, inner_gradient — CSS gradient
side_labels[6]:
title, title_color, desc (HTML)
Figma 원본: Frame 1171281211 (node 66:310, 2062×957)
수학적 계산:
scale = 1280 / 2062 = 0.620694
gradient_math.py self-test 검증 완료:
safety outer: 145.28deg, prod outer: 218.84deg, trust outer: 145.90deg
main circle: 17% width, 역삼각형 배치
ring: 14.1% width, border 4px white, box-shadow 0 0 10px
accent outer: 6.35% opacity 0.3, inner: 4.0% border 2px white
blend: mix-blend-mode: multiply (R10: plus-darker→multiply)
CSS 요소: 모든 원/gradient/shadow/blend (순수 CSS, bim-goals-3circles.html에서 검증 완료)
이미지 요소: bg_texture(실사), arc(곡선 3개)
-->
<div class="block-c3i">
{% if bg_texture_img %}
<div class="c3i-bg"><img src="{{ bg_texture_img | default('svg/bg_texture.png') }}" alt=""></div>
{% endif %}
{% if arc_img %}
<div class="c3i-arc c3i-arc--top"><img src="{{ arc_img | default('svg/arc_top.png') }}" alt=""></div>
<div class="c3i-arc c3i-arc--left"><img src="{{ arc_img | default('svg/arc_side.png') }}" alt=""></div>
<div class="c3i-arc c3i-arc--right"><img src="{{ arc_img | default('svg/arc_side.png') }}" alt=""></div>
{% endif %}
{% for c in circles %}
<div class="c3i-main c3i-main--{{ loop.index }}" style="background: {{ c.outer_gradient }};"></div>
<div class="c3i-ring c3i-ring--{{ loop.index }}" style="background: {{ c.ring_gradient }};"></div>
<div class="c3i-label c3i-label--{{ loop.index }}"
{% if c.text_shadow %}style="text-shadow: 0 0 5px {{ c.text_shadow }};"{% endif %}>
{{ c.label|safe }}
</div>
{% endfor %}
{% for a in accents %}
<div class="c3i-acc-outer c3i-acc-outer--{{ loop.index }}" style="background: {{ a.outer_gradient }};"></div>
<div class="c3i-acc-inner c3i-acc-inner--{{ loop.index }}" style="background: {{ a.inner_gradient }};"></div>
<div class="c3i-acc-char c3i-acc-char--{{ loop.index }}">{{ a.char }}</div>
{% endfor %}
{% for s in side_labels %}
<div class="c3i-side c3i-side--{{ loop.index }}">
<div class="c3i-side-title" style="color: {{ s.title_color|default('#cc5200') }};">{{ s.title }}</div>
{% if s.desc %}<div class="c3i-side-desc">{{ s.desc|safe }}</div>{% endif %}
</div>
{% endfor %}
</div>
<style>
.block-c3i {
position: relative; width: 100%;
aspect-ratio: 2.154 / 1; overflow: hidden; word-break: keep-all;
}
.c3i-bg {
position: absolute; left: 7%; bottom: 0; width: 86%; height: 29%;
mix-blend-mode: multiply; pointer-events: none;
}
.c3i-bg img { width: 100%; height: 100%; object-fit: cover; }
/* arc: 이미지 유지 (곡선 CSS 불가) */
.c3i-arc { position: absolute; z-index: 2; }
.c3i-arc img { display: block; }
.c3i-arc--top { left: 44.9%; top: 14%; width: 10.1%; height: 10.3%; }
.c3i-arc--top img { width: 100%; height: 100%; transform: rotate(180deg); }
.c3i-arc--left { left: 30.4%; top: 57.4%; width: 4.8%; height: 21.8%; }
.c3i-arc--left img { width: 218%; height: 47.4%; transform: rotate(90deg); transform-origin: center; }
.c3i-arc--right { left: 64.5%; top: 57.4%; width: 4.8%; height: 21.8%; }
.c3i-arc--right img { width: 218%; height: 47.4%; transform: rotate(-90deg); transform-origin: center; }
/* main 3원: CSS gradient + blend multiply (R10) */
.c3i-main {
position: absolute; width: 17%; aspect-ratio: 1;
border-radius: 50%; mix-blend-mode: multiply; z-index: 3;
}
.c3i-main--1 { left: 41.4%; top: 21.5%; }
.c3i-main--2 { left: 33.7%; top: 50.2%; }
.c3i-main--3 { left: 48.9%; top: 50.2%; }
/* ring: CSS gradient + white border + shadow */
.c3i-ring {
position: absolute; width: 14.1%; aspect-ratio: 1;
border-radius: 50%; border: 4px solid #fff;
box-shadow: 0 0 10px 0 rgba(0,0,0,1); z-index: 4;
}
.c3i-ring--1 { left: 42.8%; top: 24.5%; }
.c3i-ring--2 { left: 35.3%; top: 53.7%; }
.c3i-ring--3 { left: 50.6%; top: 53.7%; }
.c3i-label {
position: absolute; width: 12.8%;
font-weight: 700; font-size: 24px; color: #fff;
text-align: center; line-height: 1; letter-spacing: -0.05em;
display: flex; flex-direction: column;
align-items: center; justify-content: center; z-index: 5;
}
.c3i-label--1 { left: 43.5%; top: 34.5%; }
.c3i-label--2 { left: 35.8%; top: 63.2%; }
.c3i-label--3 { left: 51.1%; top: 62.4%; }
/* accent 6원 */
.c3i-acc-outer {
position: absolute; width: 6.35%; aspect-ratio: 1;
border-radius: 50%; opacity: 0.3; mix-blend-mode: multiply; z-index: 6;
}
.c3i-acc-inner {
position: absolute; width: 4.0%; aspect-ratio: 1;
border-radius: 50%; border: 2px solid #fff;
box-shadow: 0 0 10px 0 rgba(0,0,0,1); z-index: 7;
}
.c3i-acc-outer--1 { left: 41.7%; top: 2.3%; }
.c3i-acc-outer--2 { left: 51.9%; top: 2.3%; }
.c3i-acc-outer--3 { left: 26.9%; top: 50.5%; }
.c3i-acc-outer--4 { left: 26.9%; top: 72.0%; }
.c3i-acc-outer--5 { left: 66.5%; top: 50.5%; }
.c3i-acc-outer--6 { left: 66.5%; top: 72.0%; }
.c3i-acc-inner--1 { left: 42.8%; top: 4.7%; }
.c3i-acc-inner--2 { left: 53.0%; top: 4.7%; }
.c3i-acc-inner--3 { left: 28.1%; top: 52.9%; }
.c3i-acc-inner--4 { left: 28.1%; top: 74.4%; }
.c3i-acc-inner--5 { left: 67.7%; top: 52.9%; }
.c3i-acc-inner--6 { left: 67.7%; top: 74.4%; }
.c3i-acc-char {
position: absolute; width: 4.8%;
font-weight: 700; font-size: 22px; color: #fff;
text-align: center; letter-spacing: -0.05em;
text-shadow: 0 0 5px #cc5200;
display: flex; align-items: center; justify-content: center; z-index: 8;
}
.c3i-acc-char--1 { left: 42.4%; top: 6.6%; }
.c3i-acc-char--2 { left: 52.7%; top: 6.6%; }
.c3i-acc-char--3 { left: 27.7%; top: 54.8%; }
.c3i-acc-char--4 { left: 27.7%; top: 76.3%; }
.c3i-acc-char--5 { left: 67.3%; top: 54.8%; }
.c3i-acc-char--6 { left: 67.3%; top: 76.3%; }
/* side labels */
.c3i-side { position: absolute; z-index: 5; }
.c3i-side-title { font-weight: 700; font-size: 20px; line-height: 1.8; white-space: nowrap; }
.c3i-side-desc { font-weight: 500; font-size: 15px; color: #525151; line-height: 1.3; }
.c3i-side--1 { right: 60%; top: 0; text-align: right; }
.c3i-side--2 { left: 60%; top: 0; }
.c3i-side--3 { right: 74%; top: 47.6%; text-align: right; }
.c3i-side--4 { right: 74%; top: 69.1%; text-align: right; }
.c3i-side--5 { left: 73.6%; top: 47.6%; }
.c3i-side--6 { left: 73.6%; top: 69.4%; }
</style>
@@ -0,0 +1,135 @@
<!-- 이슈 쌍 행: 좌/우 pill(두루마리 이미지) + 2열 텍스트 박스 -->
<!--
📋 issues-paired-rows
─────────────────
용도: 좌/우 대비되는 이슈를 쌍으로 나열. pill(두루마리)이 박스 위/아래로 걸침.
슬롯:
header (icon, title) — 선택
pill_bg — 두루마리 배경 이미지 (R16 프레임 배치, crop 대상이므로 이미지 유지)
rows[] (left {label, text}, right {label, text}, pills_bottom: bool)
Figma 원본: Frame 1171281194 (node 45:19, 1857×1326)
수학적 계산:
scale = 1280 / 1857 = 0.68933
pill: 458×95.6, width=24.7% of row
pill R16 이미지 프레임: left:-45.3% width:145.3% (좌), left:0 width:151.25% (우)
bottom pill: rotate(180deg) + 이미지 반전
text: 36px → 25px, lh 65px → 45px
pill label: 40px → 28px
box: border 3px #60a451, radius 30px, bg rgba(250,237,203,0.15) (MCP 확인)
divider: 1px dashed rgba(96,164,81,0.4)
CSS 요소: box border/bg/radius, divider, header gradient text
이미지 요소: pill_bg (두루마리, R16 crop), header icon
-->
<div class="block-ipr">
{% if header %}
<div class="ipr-header">
{% if header.icon %}<div class="ipr-header-icon"><img src="{{ header.icon | default('svg/icon_header.png') }}" alt=""></div>{% endif %}
<div class="ipr-header-title">{{ header.title }}</div>
</div>
{% endif %}
<div class="ipr-rows">
{% for row in rows %}
<div class="ipr-row">
{% if not row.pills_bottom %}
<div class="ipr-pills ipr-pills--top">
<div class="ipr-pill ipr-pill--left">
{% if pill_bg %}<img src="{{ pill_bg | default('svg/pill_scroll.png') }}" alt="">{% endif %}
<span class="ipr-pill-label">{{ row.left.label }}</span>
</div>
<div class="ipr-pill ipr-pill--right">
{% if pill_bg %}<img src="{{ pill_bg | default('svg/pill_scroll.png') }}" alt="">{% endif %}
<span class="ipr-pill-label">{{ row.right.label }}</span>
</div>
</div>
{% endif %}
<div class="ipr-text-row">
<div class="ipr-text">{{ row.left.text|safe }}</div>
<div class="ipr-divider"></div>
<div class="ipr-text ipr-text--right">{{ row.right.text|safe }}</div>
</div>
{% if row.pills_bottom %}
<div class="ipr-pills ipr-pills--bottom">
<div class="ipr-pill ipr-pill--left">
{% if pill_bg %}<img src="{{ pill_bg | default('svg/pill_scroll.png') }}" alt="">{% endif %}
<span class="ipr-pill-label">{{ row.left.label }}</span>
</div>
<div class="ipr-pill ipr-pill--right">
{% if pill_bg %}<img src="{{ pill_bg | default('svg/pill_scroll.png') }}" alt="">{% endif %}
<span class="ipr-pill-label">{{ row.right.label }}</span>
</div>
</div>
{% endif %}
</div>
{% endfor %}
</div>
</div>
<style>
.block-ipr {
display: flex; flex-direction: column;
width: 100%; word-break: keep-all; padding: 12px 16px;
}
/* header: MCP 확인 gradient(#cc5200→#883700) */
.ipr-header { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.ipr-header-icon { width: 28px; height: 28px; flex: none; }
.ipr-header-icon img { width: 100%; height: 100%; object-fit: contain; }
.ipr-header-title {
font-weight: 700; font-size: 32px;
background-image: linear-gradient(180deg, #cc5200 0%, #883700 100%);
-webkit-background-clip: text; background-clip: text; color: transparent;
text-shadow: 0 0 4px rgba(50,44,30,0.4);
}
.ipr-rows { display: flex; flex-direction: column; gap: 6px; }
/* box: MCP 확인 border=#60a451, radius=30px, bg=rgba(250,237,203,0.15) */
.ipr-row {
border: 2px solid #60a451; border-radius: 16px;
background: rgba(250,237,203,0.15);
display: flex; flex-direction: column;
}
/* pill 배치: 두루마리 이미지(R16 crop) */
.ipr-pills { display: flex; justify-content: space-between; }
.ipr-pills--top { margin-top: -1.8rem; }
.ipr-pills--bottom { margin-bottom: -1.8rem; }
.ipr-pill {
position: relative; width: 25%; height: 3.8rem;
overflow: hidden; flex: none;
}
/* R16: 좌pill 우측 곡선만 보임, 우pill 좌측 곡선만 보임 */
.ipr-pill--left img {
position: absolute; top: 0; height: 100%;
left: -45.3%; width: 145.3%;
}
.ipr-pill--right img {
position: absolute; top: 0; height: 100%;
left: 0; width: 151.25%;
}
/* bottom: rotate(180) + 이미지 반전 */
.ipr-pills--bottom .ipr-pill { transform: rotate(180deg); }
.ipr-pills--bottom .ipr-pill--left img { left: 0; width: 151.25%; }
.ipr-pills--bottom .ipr-pill--right img { left: -45.3%; width: 145.3%; }
.ipr-pill-label {
position: absolute; inset: 0;
display: flex; align-items: center; justify-content: center;
font-weight: 700; font-size: 20px; color: #fff;
white-space: nowrap; z-index: 2;
}
.ipr-pills--bottom .ipr-pill-label { transform: rotate(180deg); }
/* 텍스트: 2열 grid */
.ipr-text-row { display: grid; grid-template-columns: 1fr 1px 1fr; padding: 8px 12px; }
.ipr-divider { border-left: 1px dashed rgba(96,164,81,0.4); margin: 4px 0; }
.ipr-text {
font-weight: 500; font-size: 18px; line-height: 1.8;
color: #0c271e; padding: 4px 10px;
}
.ipr-text--right { text-align: right; }
</style>
@@ -0,0 +1,119 @@
<!-- 2×2 사분면 이슈: CSS gradient ribbon + CSS card-bg + 중앙 인용구(이미지) -->
<!--
📋 quadrant-2x2-issues
─────────────────
용도: 4개 카테고리 이슈를 2×2 사분면으로 배치, 중앙에 인용구 원형 배지
슬롯:
quadrants[4] (ribbon_title, sections[{headline, bullets[]}])
center_quote (bg_img — 원형 일러스트 이미지 유지, text — HTML)
Figma 원본: Frame 1171281193 (node 45:18, 2226×1766)
수학적 계산:
scale = 1280 / 2226 = 0.575022
ribbon: 1080×119, radius=50px (SVG path r=50)
SVG gradient_math.py:
TL/BL: linear-gradient(270deg, rgba(165,161,150,0.5) -26.87%, #39321E 73.13%)
TR/BR: linear-gradient(90deg, rgba(41,107,85,0.5) 0%, #032118 100%)
card-bg: 픽셀 분석 gradient(180deg, #f2f2f2→#ffffff)
headline: #ff0000 Bold, body: #000 Regular (MCP 확인)
CSS 요소: ribbon gradient, card-bg gradient, headline/body text
이미지 요소: center_quote bg (원형 일러스트, 복잡한 radial gradient)
-->
<div class="block-q2i">
<div class="q2i-grid">
{% for q in quadrants %}
<div class="q2i-quad q2i-quad--{{ loop.index }}">
<div class="q2i-card-bg {{ 'q2i-card-bg--bottom' if loop.index > 2 }}"></div>
<div class="q2i-ribbon {{ 'q2i-ribbon--warm' if loop.index in [1,3] else 'q2i-ribbon--teal' }} {{ 'q2i-ribbon--bottom' if loop.index > 2 }}">
<div class="q2i-ribbon-text">{{ q.ribbon_title }}</div>
</div>
<div class="q2i-content">
{% for sec in q.sections %}
<div class="q2i-section">
{% if sec.headline %}<div class="q2i-headline">{{ sec.headline }}</div>{% endif %}
{% if sec.bullets %}
<ul class="q2i-bullets">
{% for b in sec.bullets %}<li>{{ b }}</li>{% endfor %}
</ul>
{% endif %}
</div>
{% endfor %}
</div>
</div>
{% endfor %}
</div>
{% if center_quote %}
<div class="q2i-center">
{% if center_quote.bg_img %}<img src="{{ center_quote.bg_img | default('svg/circle_quote.png') }}" class="q2i-center-bg" alt="">{% endif %}
<div class="q2i-center-text">{{ center_quote.text|safe }}</div>
</div>
{% endif %}
</div>
<style>
.block-q2i { position: relative; width: 100%; word-break: keep-all; }
.q2i-grid { display: grid; grid-template-columns: 1fr 1fr; }
.q2i-quad {
position: relative; display: flex; flex-direction: column;
padding: 4px 8px; min-height: 200px;
}
/* 우측 사분면: 우정렬 */
.q2i-quad--2 .q2i-headline, .q2i-quad--4 .q2i-headline { text-align: right; }
.q2i-quad--2 .q2i-bullets, .q2i-quad--4 .q2i-bullets { text-align: right; list-style-position: inside; padding-left: 0; }
/* card-bg: CSS gradient (픽셀 분석) */
.q2i-card-bg {
width: 100%; height: 80px;
border-radius: 18px 18px 0 0;
background: linear-gradient(180deg, #f2f2f2 0%, #ffffff 100%);
}
.q2i-card-bg--bottom {
border-radius: 0 0 18px 18px; order: 10;
background: linear-gradient(0deg, #f2f2f2 0%, #ffffff 100%);
}
/* ribbon: CSS gradient (SVG gradient_math.py 계산) */
.q2i-ribbon {
width: 100%; height: 44px; border-radius: 18px;
display: flex; align-items: center; justify-content: center;
}
.q2i-ribbon--bottom { order: 10; }
.q2i-ribbon--warm { background: linear-gradient(270deg, rgba(165,161,150,0.5) -26.87%, #39321E 73.13%); }
.q2i-ribbon--teal { background: linear-gradient(90deg, rgba(41,107,85,0.5) 0%, #032118 100%); }
.q2i-ribbon-text {
font-weight: 900; font-size: 22px; color: #fff;
text-shadow: 0 0 4px #322c1e; white-space: nowrap;
}
.q2i-content { flex: 1; display: flex; flex-direction: column; gap: 8px; padding: 6px 4px; }
/* headline: MCP 확인 #ff0000 Bold */
.q2i-headline { font-weight: 700; font-size: 18px; color: #ff0000; line-height: 1.3; }
/* body: MCP 확인 #000 Regular */
.q2i-bullets {
list-style: disc; margin: 0; padding-left: 28px;
font-weight: 400; font-size: 15px; color: #000; line-height: 1.5;
}
.q2i-bullets li { word-break: keep-all; }
/* center quote: 이미지 유지 (원형 일러스트) */
.q2i-center {
position: absolute; top: 50%; left: 50%;
transform: translate(-50%, -50%);
width: 200px; height: 180px;
display: flex; align-items: center; justify-content: center; z-index: 5;
}
.q2i-center-bg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; }
.q2i-center-text {
position: relative; z-index: 1;
font-weight: 700; font-size: 20px; color: #fff;
text-align: center; line-height: 1.3;
}
</style>
@@ -0,0 +1,172 @@
<!-- 분할 패널: 좌측 카테고리 + 우측 번호 설명 -->
<!--
📋 split-panel-numbered
─────────────────
용도: 좌측 카테고리별 항목 + 우측 번호 설명 2단 배치
슬롯:
title_icon — 아이콘 이미지
title (HTML — <span class="model">, <span class="sub">)
left_bg_color — 좌측 셰브론 배경 CSS gradient (기본값 제공)
categories[] (name, color, items[])
mid_arrow_img — 중간 화살표 이미지
right_items[] (number, text, badge_img)
arrow_img — 우측 화살표 이미지
Figma 원본: Frame 1171281202 (node 45:27, 1863×834)
수학적 계산:
scale = 1280 / 1863 = 0.68706
title: Model=70px gradient(#cc5200→#883700), sub=50px gradient(#296b55→#000) (MCP 확인)
cat bar: 단색 #417d38, #008e52, #008970 (픽셀 분석, MCP=이미지)
right bar: #e8ede3 단색 (픽셀 분석)
left-bg: 셰브론 형태 + alpha gradient (픽셀 분석)
CSS 요소: title gradient text, cat bars, right bars, left-bg, mid-deco
이미지 요소: title icon, 3D badge(일러스트), arrow(아이콘), mid arrow
-->
<div class="block-spn">
{% if title_icon or title %}
<div class="spn-header">
{% if title_icon %}<div class="spn-title-icon"><img src="{{ title_icon | default('svg/icon_title.png') }}" alt=""></div>{% endif %}
{% if title %}<div class="spn-title">{{ title|safe }}</div>{% endif %}
</div>
{% endif %}
<div class="spn-body">
<!-- 좌측 패널 -->
<div class="spn-left">
<div class="spn-left-bg"></div>
<div class="spn-categories">
{% for cat in categories %}
<div class="spn-cat">
<div class="spn-cat-bar" style="background: {{ cat.color|default('#417d38') }};"></div>
<div class="spn-cat-title">{{ cat.name }}</div>
<div class="spn-cat-items">
{% for item in cat.items %}
<div class="spn-cat-item">· {{ item }}</div>
{% endfor %}
</div>
</div>
{% endfor %}
</div>
</div>
<!-- 중간 장식 -->
<div class="spn-mid">
<div class="spn-mid-deco"></div>
{% if mid_arrow_img %}<img src="{{ mid_arrow_img | default('svg/arrow_mid.png') }}" class="spn-mid-arrow" alt="">{% endif %}
</div>
<!-- 우측 패널 -->
<div class="spn-right">
{% for item in right_items %}
<div class="spn-row">
{% if item.badge_img %}<div class="spn-badge"><img src="{{ item.badge_img }}" alt=""></div>
{% elif loop.index <= 5 %}<div class="spn-badge"><img src="svg/badge_num_0{{ loop.index }}.png" alt=""></div>{% endif %}
<div class="spn-row-bar">
<div class="spn-row-text">{{ item.text }}</div>
{% if arrow_img %}<img src="{{ arrow_img | default('svg/arrow_right.png') }}" class="spn-row-arrow" alt="">{% endif %}
</div>
</div>
{% endfor %}
</div>
</div>
</div>
<style>
.block-spn {
display: flex; flex-direction: column;
width: 100%; height: 100%;
word-break: keep-all;
}
.spn-header { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.spn-title-icon { flex: none; width: 26px; height: 27px; }
.spn-title-icon img { width: 100%; height: 100%; object-fit: contain; }
/* title: MCP 확인 gradient text */
.spn-title { font-weight: 900; line-height: 1.1; white-space: nowrap; }
.spn-title .model {
font-size: 34px;
background-image: linear-gradient(180deg, #cc5200 0%, #883700 100%);
-webkit-background-clip: text; background-clip: text; color: transparent;
}
.spn-title .sub {
font-size: 24px;
background-image: linear-gradient(180deg, #296b55 0%, #000 100%);
-webkit-background-clip: text; background-clip: text; color: transparent;
}
.spn-body { display: flex; flex: 1; }
/* 좌측: 셰브론 배경 (CSS clip-path + gradient) */
.spn-left { position: relative; flex: 52; overflow: hidden; }
.spn-left-bg {
position: absolute; inset: 0;
background: linear-gradient(90deg,
rgba(192,213,208,0.19) 0%, rgba(195,214,209,0.66) 50%, rgba(211,227,226,1) 95%);
clip-path: polygon(0 0, 82% 0, 100% 50%, 82% 100%, 0 100%);
border-radius: 20px 0 0 20px;
}
.spn-categories {
position: relative; z-index: 1;
display: flex; flex-direction: column;
justify-content: space-between; flex: 1;
padding: 8px 16px;
}
.spn-cat { display: flex; flex-direction: column; }
/* cat bar: CSS 단색 (픽셀 분석, Figma=이미지) */
.spn-cat-bar {
height: 34px; border-radius: 5px;
background: linear-gradient(90deg, currentColor 0%, currentColor 85%, transparent 100%);
margin-bottom: 4px;
}
.spn-cat-title {
position: relative; z-index: 1; margin-top: -30px;
font-size: 20px; font-weight: 700; color: #fff;
text-shadow: 0 0 4px rgba(0,0,0,0.5);
padding-left: 12px; line-height: 34px;
}
.spn-cat-items { padding: 4px 12px; }
.spn-cat-item {
font-size: 16px; font-weight: 500; color: #000;
line-height: 1.6; text-shadow: 0 0 4px rgba(0,0,0,0.5);
}
/* 중간 장식: CSS radial-gradient */
.spn-mid {
position: relative; flex: none; width: 8%;
display: flex; align-items: center; justify-content: center;
}
.spn-mid-deco {
position: absolute; inset: 10% 0;
background: radial-gradient(ellipse 60% 50% at 100% 50%,
rgba(217,217,217,0.8) 0%, rgba(217,217,217,0.13) 60%, transparent 100%);
}
.spn-mid-arrow { position: relative; z-index: 1; width: 50px; height: 108px; object-fit: contain; }
/* 우측: 번호 + 설명 */
.spn-right {
flex: 40; display: flex; flex-direction: column;
justify-content: space-between; padding: 4px 0;
}
.spn-row { display: flex; align-items: center; gap: 4px; }
/* badge: 3D 큐브 일러스트 → 이미지 유지 */
.spn-badge { flex: none; width: 42px; height: 44px; z-index: 2; }
.spn-badge img { width: 100%; height: 100%; object-fit: contain; }
/* right bar: CSS #e8ede3 (픽셀 분석) */
.spn-row-bar {
flex: 1; display: flex; align-items: center;
min-height: 48px; padding: 8px 16px;
background: #e8ede3; border-radius: 10px;
}
.spn-row-text {
flex: 1; font-size: 18px; font-weight: 500;
color: #11231d; line-height: 1.4;
}
.spn-row-arrow {
flex: none; width: 22px; height: 21px;
transform: rotate(180deg); object-fit: contain;
}
</style>
@@ -0,0 +1,133 @@
<!-- 적층 화살표 리스트: CSS title bar + 좌측 아크(이미지) + 다이아몬드형 행 -->
<!--
📋 stacked-arrow-list
─────────────────
용도: 핵심 항목 N개를 다이아몬드(원호) 형태로 적층 표시
슬롯:
title (HTML — <em>으로 강조)
left_label (HTML — <br>로 줄바꿈)
left_arc_img — 좌측 곡선 장식 (이미지, CSS 곡선 불가)
arrow_img — 화살표 아이콘 (이미지)
items[] (text, border_color)
Figma 원본: Frame 1171281180 (node 45:5, 1153×592)
수학적 계산:
scale = 1280 / 1153 = 1.11014 (확대)
title bar: Figma bg=#fbd5b9, radius=5px, shadow=0 4px 4px rgba(0,0,0,0.25) (MCP 확인)
title: 43px Bold #144838, highlight: 50px gradient(#cc5200) (MCP 확인)
row: bg=rgba(255,255,255,0.5), radius=30px, shadow=2px 4px 5px rgba(0,0,0,0.5) (MCP 확인)
border 색상: #fb5915, #e79000, #e9a804, #919f00, #0d6361 (MCP 확인)
행 다이아몬드 indent: [0%, 6%, 9%, 6%, 0%]
CSS 요소: title bar, row bg/border/shadow
이미지 요소: arc(곡선), arrow(아이콘)
-->
<div class="block-sal">
{% if title %}
<div class="sal-header">
<div class="sal-title-bar"></div>
<div class="sal-title">{{ title|safe }}</div>
</div>
{% endif %}
<div class="sal-body">
{% if left_arc_img or left_label %}
<div class="sal-deco">
{% if left_arc_img %}<img src="{{ left_arc_img | default('svg/arc_left.svg') }}" class="sal-arc" alt="">{% endif %}
{% if left_label %}<div class="sal-label">{{ left_label|safe }}</div>{% endif %}
</div>
{% endif %}
<div class="sal-rows">
{% for item in items %}
<div class="sal-row" style="--bc: {{ item.border_color|default('#fb5915') }};">
{% if arrow_img %}
<div class="sal-arrow"><img src="{{ arrow_img | default('svg/arrow_down.svg') }}" alt=""></div>
{% endif %}
<div class="sal-text">{{ item.text }}</div>
</div>
{% endfor %}
</div>
</div>
</div>
<style>
.block-sal {
display: flex; flex-direction: column;
width: 100%;
word-break: keep-all;
}
/* ── 헤더 ── */
.sal-header { position: relative; margin-bottom: 12px; }
/* title bar: MCP 확인 bg=#fbd5b9, radius=5px, shadow */
.sal-title-bar {
position: absolute;
left: 1%; top: 50%;
width: 98%; height: 32px;
background: #fbd5b9;
border-radius: 5px;
box-shadow: 0 4px 4px rgba(0,0,0,0.25);
transform: translateY(-30%);
}
/* title: MCP 확인 #144838, highlight gradient(#cc5200) */
.sal-title {
position: relative; z-index: 1;
font-size: 26px; font-weight: 700;
color: #144838;
text-align: center;
line-height: 1.4;
letter-spacing: -0.04em;
}
.sal-title em {
font-style: normal; font-weight: 900; font-size: 30px;
background-image: linear-gradient(90deg, #cc5200 0%, #cc5200 100%);
-webkit-background-clip: text; background-clip: text; color: transparent;
}
.sal-body { display: flex; align-items: stretch; flex: 1; }
/* 좌측: arc 이미지 + 세로 라벨 */
.sal-deco {
position: relative; flex: none; width: 14%;
display: flex; align-items: center; justify-content: center;
}
.sal-arc {
position: absolute; right: 0; top: 0;
width: 100%; height: 100%;
object-fit: contain; object-position: right center;
}
.sal-label {
position: relative; z-index: 1;
font-size: 26px; font-weight: 700; color: #144838;
text-align: center; line-height: 1.5;
text-shadow: 0 4px 4px rgba(0,0,0,0.25);
}
/* 행: MCP 확인 bg, radius, shadow, border-bottom */
.sal-rows {
flex: 1; display: flex; flex-direction: column;
justify-content: space-between; gap: 8px; padding: 8px 0;
}
.sal-row {
display: flex; align-items: center; gap: 12px;
padding: 12px 20px;
background: rgba(255,255,255,0.5);
border-radius: 30px;
box-shadow: 2px 4px 5px rgba(0,0,0,0.5);
border-bottom: 3px solid var(--bc, #fb5915);
}
.sal-row:nth-child(1) { margin-left: 0; }
.sal-row:nth-child(2) { margin-left: 6%; }
.sal-row:nth-child(3) { margin-left: 9%; }
.sal-row:nth-child(4) { margin-left: 6%; }
.sal-row:nth-child(5) { margin-left: 0; }
.sal-arrow { flex: none; width: 19px; height: 25px; transform: rotate(-90deg); }
.sal-arrow img { width: 100%; height: 100%; }
.sal-text {
flex: 1; font-size: 22px; font-weight: 500;
color: #000; line-height: 1.5; letter-spacing: -0.03em;
}
</style>
@@ -0,0 +1,61 @@
<!-- 선언문 pill 강조: CSS gradient 캡슐 배경 + 센터 텍스트 + 하이라이트 -->
<!--
📋 statement-pill-highlight
─────────────────
용도: 핵심 선언/결론 메시지를 캡슐형 배경 위에 한 줄로 강조
슬롯: text (HTML — <em>으로 하이라이트)
Figma 원본: Frame 1171281207 (node 51:170, 3547×163)
수학적 계산:
scale = 1280 / 3547 = 0.36087
pill height: 163 × S ≈ 59px → padding 기반 (텍스트 양 대응)
font: 80px × S ≈ 29px, line-height: 90/80 = 1.125
border-radius: 97px (Figma) → capsule (999px)
색상 (CSS — AI 조정 가능):
배경 gradient: 픽셀 분석 #3b3523(5%)→#263a2a(50%)→#113f31(95%)
텍스트: #ffffff, Bold 700
하이라이트(<em>): #ffee33
text-shadow: 0 0 4px rgba(0,0,0,0.5)
이미지 의존: 없음 (순수 CSS)
-->
<div class="block-sph">
<div class="sph-pill">
<div class="sph-text">{{ text|safe }}</div>
</div>
</div>
<style>
.block-sph {
display: flex; align-items: center; justify-content: center;
width: 100%;
}
/*
캡슐: Figma 3547×163, border-radius 97 → 999px
배경: 픽셀 분석 기반 CSS gradient (원본에 미세 네트워크 텍스처 있었으나 생략)
*/
.sph-pill {
width: 100%;
min-height: 59px;
border-radius: 999px;
background: linear-gradient(90deg, #3b3523 5%, #263a2a 50%, #113f31 95%);
display: flex; align-items: center; justify-content: center;
padding: 14px 48px;
}
/* 텍스트: Figma 80px/90px Bold white → scaled 29px */
.sph-text {
font-size: 29px;
font-weight: 700;
color: #ffffff;
text-align: center;
line-height: 1.125;
text-shadow: 0 0 4px rgba(0,0,0,0.5);
word-break: keep-all;
}
/* <em> 하이라이트: Figma #ffee33 */
.sph-text em {
color: #ffee33;
font-style: normal;
}
</style>
@@ -1,16 +1,19 @@
<!-- 히어로 카드 변형1: 3D 리본 배지 + N열 카드 (제목+제목+불릿 계층) -->
<!-- 히어로 카드 변형1: 3D 리본 배지 + N열 카드 (제목+제목+불릿 계층) -->
<!--
📋 hero-icon-cards_1
─────────────────
용도: 핵심 요건/목표를 N열 카드로 시각화. 각 카드에 제목+제목+불릿 계층.
용도: 핵심 요건/목표를 N열 카드로 시각화. 각 카드에 제목+제목+불릿 계층.
슬롯: statement(선택), badge_title, cards[] (title, sections[{title, bullets[]}])
변형 원본: hero-icon-cards
변경점: icon/title/subtitle → sections[{title, bullets[]}] 계층으로 변경
수학적 계산: hero-icon-cards와 동일
badge 508x94 at y=1431, box at y=1449, frame_w=1808
scale = 1200/1808 = 0.6637
ribbon: 337x62px, fold_offset: 12px, ribbon_below_fold: 50px
box padding-top: 56px
변경점:
- icon/subtitle → sections[{title, bullets[]}] 계층으로 변경
- 배경 #0a0a0a 제거
- 슬라이드(1280x720) 기준 글씨 크기
수학적 계산 (답안지 PNG 기준):
상단 블록 영역: 약 280px
중제목: 16px, 소제목: 13px, 불릿: 12px
리본: 원본 비율 유지, 텍스트 14px
박스 padding-top: 36px (리본 공간)
-->
<div class="block-hic">
{% if statement %}
@@ -20,7 +23,7 @@
<div class="hic-card-area">
{% if badge_title %}
<div class="hic-ribbon">
<img src="{{ ribbon_image | default('../../../static/figma-assets/badge_solution.png') }}" class="hic-ribbon-img" alt="">
<img src="{{ ribbon_image | default('svg/badge_solution.png') }}" class="hic-ribbon-img" alt="">
<span class="hic-ribbon-text">{{ badge_title }}</span>
</div>
{% endif %}
@@ -50,22 +53,13 @@
width: 100%; overflow: visible;
}
/* ── Hero Statement ── */
.hic-statement {
text-align: center; font-size: 16px; font-weight: var(--weight-bold, 700);
color: #1e293b; line-height: 1.6; word-break: keep-all;
margin-bottom: 8px; padding: 0 24px;
margin-bottom: 8px;
}
.hic-statement strong { font-weight: 900; font-size: 1.1em; }
.hic-statement em { color: #ef4444; font-style: normal; font-weight: 900; font-size: 1.15em; }
/*
리본+박스 수학적 계산 (Figma 원본):
badge 508x94 at y=1431, box at y=1449
접힘선 = 18px = 이미지 높이의 19.1%
scale(1200/1808) → ribbon 337x62, fold top에서 12px, 아래 50px
*/
.hic-card-area { position: relative; width: 100%; }
.hic-card-area { position: relative; width: 100%; margin-top: 4px; }
.hic-ribbon {
position: absolute;
@@ -81,31 +75,30 @@
text-shadow: 0 1px 3px rgba(0,0,0,0.3);
}
/* 얇은 테두리 박스 */
.hic-box {
position: relative; background: #fff;
border: 1px solid #e2e8f0; border-radius: 8px;
padding: 36px 8px 8px;
border: 6px solid #9b1b1b; border-radius: 20px;
padding: 36px 8px 10px;
}
.hic-cards { display: flex; align-items: stretch; width: 100%; }
.hic-card {
flex: 1; display: flex; flex-direction: column;
padding: 8px 10px 10px; gap: 0;
align-items: center; justify-content: flex-start; text-align: center;
padding: 8px 16px 12px; gap: 0;
}
.hic-sep { width: 1px; background: #e0e0e0; align-self: stretch; margin: 4px 0; }
.hic-sep { width: 1px; background: #e0e0e0; align-self: stretch; margin: 6px 0; }
/* ── 카드 내부 (변형: icon → 소제목+불릿 계층) ── */
/* 중제목 (카드 헤더: 기술/사람/자연): 중앙 정렬 */
.hic-title { font-size: 14px; font-weight: var(--weight-black, 900); color: #0d7377; line-height: 1.3; text-align: center; margin-bottom: 6px; }
/* 소제목 (D1): 12px/700, 들여쓰기 1단 */
.hic-sec-title { font-size: 12px; font-weight: 700; color: #1a1a1a; line-height: 1.4; margin-top: 6px; margin-bottom: 2px; padding-left: 8px; }
.hic-sec-title:first-of-type { margin-top: 0; }
/* 불릿 (D2): 11px/500, 들여쓰기 2단 */
.hic-bullet {
position: relative; padding-left: 24px;
font-size: 11px; font-weight: 500; color: #334155;
line-height: 1.7; word-break: keep-all;
.hic-title { font-size: 16px; font-weight: var(--weight-black, 900); color: #1a1a1a; line-height: 1.3; margin-bottom: 10px; }
.hic-sec-title {
font-size: 13px; font-weight: var(--weight-bold, 700); color: #1a1a1a;
line-height: 1.4; margin-top: 8px; margin-bottom: 3px; text-align: left; width: 100%;
}
.hic-bullet::before { content: '•'; position: absolute; left: 14px; color: #666; }
.hic-sec-title:first-of-type { margin-top: 0; }
.hic-bullet {
position: relative; padding-left: 14px; text-align: left; width: 100%;
font-size: 11px; font-weight: var(--weight-medium, 500); color: #444;
line-height: 1.65; word-break: keep-all;
}
.hic-bullet::before { content: '•'; position: absolute; left: 0; color: #999; }
</style>
+203
View File
@@ -0,0 +1,203 @@
<!-- 슬라이드 배경 (고정) — 모든 블록의 공통 래퍼 -->
<!--
📋 slide-base
─────────────────
용도: 16:9 슬라이드의 고정 배경. 상단 제목 + 구분선 + 본문 영역 + 하단 결론 pill.
각 블록(new/, cards/, emphasis/ 등)은 본문 영역(.slide-body) 안에 들어간다.
Figma 원본: Frame 1171281207 (node 107:22, 3848×2165, Page 2)
수학적 계산:
원본 3848×2165 → 16:9 (1280×720)
scale = 1280 / 3848 = 0.33264
상단 제목: top 125px × S ≈ 42px, left 155px × S ≈ 52px, font 65.8px × S ≈ 22px
구분선: top 218px × S ≈ 72px
하단 pill: top 1980px × S ≈ 659px, height 123px × S ≈ 41px
본문 영역: top ~72px ~ bottom ~659px = 약 587px 가용
슬롯:
title — 슬라이드 제목 (gradient text)
body — {% block body %}{% endblock %} 또는 include 대상
footer_text — 하단 pill 결론 메시지 (HTML, <em> 노란 하이라이트) (선택)
이미지:
svg/bg_slide_texture.png — 배경 텍스처 (opacity 2%)
svg/line_divider.svg — 구분선
svg/pill_scroll.png — 하단 pill 배경 (두루마리, 이미지 유지)
CSS 요소:
배경 gradient: linear-gradient(180deg, #f0f0f0, #fff)
제목 gradient text: linear-gradient(180deg, #296b55, #123328)
하단 pill: 캡슐 border-radius 50px
-->
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=1280">
<title>{{ title|default("슬라이드") }}</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@500;700;900&display=swap" rel="stylesheet">
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'Noto Sans KR', sans-serif;
background: #e8ecf0;
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: #fff;
box-shadow: 0 4px 20px rgba(0,0,0,0.15);
}
/*
배경: Figma gradient(#f0f0f0→#fff) + 텍스처(opacity 2%)
MCP 확인: bg-gradient-to-b from-[#f0f0f0] to-white, opacity-2
*/
.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;
}
/*
상단 제목: Figma 65.8px Bold, gradient(#296b55→#123328)
top: 125/2165 × 720 ≈ 42px, left: 155/3848 × 1280 ≈ 52px
text-shadow: 0 0 5px #322c1e (Figma 5.263px × S)
*/
.slide-title {
position: absolute;
left: 52px; top: 22px;
width: calc(100% - 104px);
font-weight: 700;
font-size: 22px;
line-height: 1.4;
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;
}
/*
구분선: Figma top 218px → 72px, width 3553/3848 × 1280 ≈ 1181px
SVG 이미지 또는 CSS border
*/
.slide-divider {
position: absolute;
left: 50px; top: 58px;
width: calc(100% - 100px);
height: 2px;
z-index: 2;
}
.slide-divider img {
width: 100%; height: 100%;
display: block;
}
/*
본문 영역: 구분선 아래 ~ 하단 pill 위
top: ~65px, bottom: ~60px (pill 영역)
→ 가용 높이 약 595px
*/
.slide-body {
position: absolute;
left: 40px; top: 65px;
width: calc(100% - 80px);
height: 590px;
z-index: 1;
overflow: hidden;
}
/*
하단 pill: Figma top 1980/2165 × 720 ≈ 659px, height 123 × S ≈ 41px
캡슐 border-radius: 50px × S ≈ 17px → 999px (캡슐)
pill 배경: 이미지 (두루마리, R16 crop) 또는 CSS gradient
*/
.slide-footer {
position: absolute;
left: 50px; bottom: 8px;
width: calc(100% - 100px);
height: 41px;
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;
}
/* pill 배경이 이미지 없을 때 CSS gradient fallback */
.slide-footer--css {
background: linear-gradient(90deg, #3b3523 5%, #263a2a 50%, #113f31 95%);
}
/*
footer 텍스트: Figma 60px × S ≈ 20px, Bold white
<em> = 노란색 #fe3
*/
.slide-footer-text {
position: relative; z-index: 1;
font-size: 20px;
font-weight: 700;
color: #ffffff;
text-align: center;
line-height: 1.2;
text-shadow: 0 0 4px rgba(0,0,0,0.5);
letter-spacing: -0.01em;
}
.slide-footer-text em {
color: #ffee33;
font-style: normal;
}
</style>
</head>
<body>
<div class="slide">
<!-- 배경 -->
<div class="slide-bg">
<img src="svg/bg_slide_texture.png" class="slide-bg-texture" alt="">
</div>
<!-- 상단 제목 -->
<div class="slide-title">{{ title|default("슬라이드 제목") }}</div>
<!-- 구분선 -->
<div class="slide-divider">
<img src="svg/line_divider.svg" alt="">
</div>
<!-- 본문 영역 — 블록들이 여기에 들어감 -->
<div class="slide-body">
{% block body %}{% endblock %}
</div>
<!-- 하단 결론 pill -->
{% if footer_text %}
<div class="slide-footer">
{% if footer_pill_bg %}
<img src="{{ footer_pill_bg }}" class="slide-footer-bg" alt="">
{% else %}
<div class="slide-footer-bg slide-footer--css"></div>
{% endif %}
<div class="slide-footer-text">{{ footer_text|safe }}</div>
</div>
{% endif %}
</div>
</body>
</html>
+30
View File
@@ -0,0 +1,30 @@
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 210.699 489.919" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Mask group" filter="url(#filter0_d_106_321)">
<mask id="mask0_106_321" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="201" height="475">
<path id="Intersect" d="M0 58.1721C0 62.7691 3.14483 66.7452 7.5533 68.0482C80.6773 89.662 134.036 157.329 134.036 237.46C134.036 317.59 80.677 385.255 7.55332 406.868C3.14484 408.171 0 412.148 0 416.745V465.118C0 471.337 5.62415 476.059 11.6872 474.677C119.925 450.01 200.699 353.169 200.699 237.46C200.699 121.751 119.925 24.9083 11.6872 0.241745C5.62413 -1.13998 0 3.58191 0 9.80042V58.1721Z" fill="url(#paint0_linear_106_321)"/>
</mask>
<g mask="url(#mask0_106_321)">
<rect id="Rectangle 43991" y="-0.00117085" width="270" height="95" fill="var(--fill-0, #FD9164)" fill-opacity="0.8"/>
<rect id="Rectangle 43992" y="94.9988" width="270" height="95" fill="var(--fill-0, #F29700)" fill-opacity="0.8"/>
<rect id="Rectangle 43993" x="-54" y="189.999" width="270" height="95" fill="var(--fill-0, #FCC948)" fill-opacity="0.8"/>
<rect id="Rectangle 43994" y="284.999" width="270" height="95" fill="var(--fill-0, #C3D601)" fill-opacity="0.8"/>
<rect id="Rectangle 43995" y="379.999" width="270" height="95" fill="var(--fill-0, #65C6C4)" fill-opacity="0.8"/>
</g>
</g>
<defs>
<filter id="filter0_d_106_321" x="0" y="0" width="210.699" height="489.919" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dx="5" dy="10"/>
<feGaussianBlur stdDeviation="2.5"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.3 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_106_321"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_106_321" result="shape"/>
</filter>
<linearGradient id="paint0_linear_106_321" x1="121.177" y1="-3.68723" x2="22.5301" y2="487.856" gradientUnits="userSpaceOnUse">
<stop stop-color="#6FD6D8"/>
<stop offset="1" stop-color="#14706E"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

@@ -0,0 +1,9 @@
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 192 169" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Vector" d="M192 169L179.022 154.254C168.646 142.474 159.023 133.381 145.754 127.296C133.472 121.666 118.062 118.732 97.6292 118.185V165.326L0 82.663L97.6292 0V47.3981C131.266 48.7758 156.328 59.8343 172.195 80.3485C185.335 97.3587 192 120.867 192 150.291V169Z" fill="url(#paint0_linear_101_190)"/>
<defs>
<linearGradient id="paint0_linear_101_190" x1="0" y1="84.5" x2="192" y2="84.5" gradientUnits="userSpaceOnUse">
<stop/>
<stop offset="1" stop-opacity="0.3"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 677 B

+3
View File
@@ -0,0 +1,3 @@
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 22.4 16.8" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Vector" d="M21.4629 0.5L11.1191 15.8984L0.930664 0.5H21.4629Z" fill="var(--fill-0, black)" stroke="var(--stroke-0, white)"/>
</svg>

After

Width:  |  Height:  |  Size: 316 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

+3
View File
@@ -0,0 +1,3 @@
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 3553 5" fill="none" xmlns="http://www.w3.org/2000/svg">
<line id="Line 1" y1="2.5" x2="3553" y2="2.5" stroke="var(--stroke-0, #0F2E25)" stroke-width="5"/>
</svg>

After

Width:  |  Height:  |  Size: 277 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 531 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 485 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 534 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

+94
View File
@@ -0,0 +1,94 @@
<!-- 순환 궤도 다이어그램: 3D 원 Z축 기울임 → 2D 투영, N개 노드 순환 -->
<!--
📋 cycle-orbit
─────────────────
용도: N개 요소가 순환 관계를 이루는 다이어그램. 3D 원 투영 궤도 + 노드 + 화살표.
슬롯: title, nodes[] (각 노드에 icon, label, sub_label, desc_title, bullets[])
+ 파이프라인이 계산해서 전달하는 값: ellipse, node_positions[], arrow_positions[]
Figma 원본: Page 4 / Frame 1 (DX 시행을 위한 필수 요건, 1076x292)
핵심 수학 (파이프라인에서 계산):
3D 원: R=400, Z축 기울임 θ=80°
투영: project(α) = (cx + R×cos(α), cy + R×sin(α)×cos(80°))
타원: cx=500, cy=200, rx=400, ry=69
N개 노드: 하단 중심(90°) 기준 ±(360/N × 1/3)으로 배치, 사람(270°) 고정
사이각 축소: 기본 간격의 2/3 → 앞쪽 노드들이 가까워짐
화살표: 호 위 1/3, 2/3 지점에 » 마커, 접선 방향으로 회전
텍스트 배치 규칙 (Figma 원본 분석):
좌측 노드 (node_x < cx): 설명이 이름 좌측에 (text-anchor: end)
우측/상단 노드 (node_x >= cx): 설명이 이름 우측에 (text-anchor: start)
설명 제목은 노드 라벨과 같은 Y 높이, 불릿은 제목 아래 들여쓰기
-->
<div class="block-co">
{% if title %}
<div class="co-title">{{ title }}</div>
{% endif %}
<svg class="co-svg" viewBox="0 0 {{ viewbox_w | default(1000) }} {{ viewbox_h | default(380) }}" xmlns="http://www.w3.org/2000/svg">
<defs>
<marker id="co-arr" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="5" markerHeight="5" orient="auto">
<path d="M0,1 L9,5 L0,9" fill="none" stroke="#aaa" stroke-width="1.5"/>
</marker>
</defs>
<!-- 타원 궤도 (3D원 투영) -->
<ellipse cx="{{ ellipse.cx }}" cy="{{ ellipse.cy }}" rx="{{ ellipse.rx }}" ry="{{ ellipse.ry }}"
fill="none" stroke="#c0c0c0" stroke-width="1.5"/>
<!-- 화살표 >> (접선 방향 회전) -->
{% for arrow in arrows %}
<text x="{{ arrow.x }}" y="{{ arrow.y + 4 }}" text-anchor="middle" font-size="14" fill="#999"
transform="rotate({{ arrow.rotation }},{{ arrow.x }},{{ arrow.y }})">»</text>
{% endfor %}
<!-- 노드들 -->
{% for node in nodes %}
<!-- 노드: {{ node.label }} ({{ node.angle }}°) ({{ node.x }}, {{ node.y }}) -->
<circle cx="{{ node.x }}" cy="{{ node.y }}" r="26" fill="#e9e8e8" stroke="#818181" stroke-width="2.5"/>
{% if node.icon %}<text x="{{ node.x }}" y="{{ node.y + 6 }}" text-anchor="middle" font-size="18">{{ node.icon }}</text>{% endif %}
<text x="{{ node.x }}" y="{{ node.y + 44 }}" text-anchor="middle" font-size="13" font-weight="900" fill="#1e293b">{{ node.label }}</text>
{% if node.sub_label %}<text x="{{ node.x }}" y="{{ node.y + 58 }}" text-anchor="middle" font-size="9" fill="#64748b">({{ node.sub_label }})</text>{% endif %}
<!-- 설명 텍스트 (좌측 노드→좌측에, 우측/상단 노드→우측에) -->
{% if node.desc_title %}
<text x="{{ node.desc_x }}" y="{{ node.desc_y }}" text-anchor="{{ node.desc_anchor }}" font-size="12" font-weight="700" fill="#1e293b">{{ node.desc_title }}</text>
{% endif %}
{% if node.bullets is defined %}
{% for b in node.bullets %}
<text x="{{ node.bullet_x }}" y="{{ node.desc_y + 15 * (loop.index) }}" text-anchor="{{ node.desc_anchor }}" font-size="10" fill="#64748b">• {{ b }}</text>
{% endfor %}
{% endif %}
{% endfor %}
</svg>
</div>
<style>
/*
3D 원 투영 순환 궤도
파이프라인에서 모든 좌표를 계산하여 전달
이 템플릿은 좌표를 받아 SVG로 렌더링만 함
*/
.block-co {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
}
.co-title {
font-size: 18px;
font-weight: var(--weight-black, 900);
color: var(--color-primary, #1e293b);
text-align: center;
margin-bottom: 8px;
padding-bottom: 6px;
border-bottom: 2px solid var(--color-accent, #2563eb);
}
.co-svg {
width: 100%;
max-width: 900px;
font-family: 'Pretendard Variable', 'Noto Sans KR', sans-serif;
}
</style>
+1121 -499
View File
File diff suppressed because it is too large Load Diff