Files
eene_dashboard/frontend/public/quarter-dashboard-preview.html
EENE Dashboard cf72281c6d feat: quarter board theme, hub column, and team panel UX
Apply preview-style 4-dept layout with center hub, PM/assignee team status linking, task type label updates, and remove task keywords.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-08 22:09:46 +09:00

1952 lines
60 KiB
HTML

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>2026년 2분기 인사총무 프로젝트 현황 — Preview</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/static/pretendard.css" />
<style>
:root {
/* 본문 — 참고 이미지 톤 + 상단바 그린 계열 */
--hrm: #29724f;
--hrm-soft: #e8f4ef;
--hrd: #37a184;
--hrd-soft: #e6f6f0;
--ex: #4a9480;
--ex-soft: #eaf3ef;
--ga: #0d4a38;
--ga-soft: #e4ece8;
--dept-accent: #29724f;
--page-bg: #e9eef2;
--card-bg: #ffffff;
--card-border: #d8e2ea;
--card-shadow: 0 4px 18px rgba(15, 35, 52, 0.07);
--hub-border: #ccd8e2;
--postit-bg: #dceee6;
--postit-bg-deep: #cddfd7;
--postit-border: rgba(41, 114, 79, 0.14);
--postit-shadow: 0 5px 16px rgba(22, 72, 52, 0.1), 0 2px 5px rgba(15, 35, 52, 0.05);
--hub-diamond-bg: linear-gradient(145deg, #1e5c44 0%, #0d3a2a 100%);
--hub-diamond-border: #2f8a66;
--conn-line: #b8c6d4;
--conn-line-width: 4;
--text-primary: #1a2b3c;
--text-muted: #5a6b7d;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body.preview-page {
font-family:
"Pretendard Variable",
Pretendard,
-apple-system,
BlinkMacSystemFont,
system-ui,
"Malgun Gothic",
sans-serif;
background: var(--page-bg);
color: #1a2b3c;
min-height: 100vh;
display: flex;
flex-direction: column;
}
/* ─── 상단바 (DashboardHeader 동일) ─── */
.dashboard-header-bar {
display: flex;
align-items: center;
justify-content: space-between;
position: relative;
z-index: 10;
flex-shrink: 0;
height: 48px;
min-height: 48px;
padding: 0 22px 0 20px;
background: linear-gradient(180deg, #37a184 0%, #29724f 20%, #07412e 100%);
border-bottom: 1px solid #135643;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
color: #fff;
}
.side-left-group {
display: flex;
align-items: center;
gap: 16px;
height: 100%;
}
.main_tit {
display: flex;
align-items: center;
gap: 10px;
font-size: 20px;
font-weight: 700;
letter-spacing: -0.5px;
color: #bad8ca;
text-shadow:
-1px -1px 1px rgba(0, 0, 0, 0.25),
1px -1px 1px rgba(0, 0, 0, 0.25),
-1px 1px 1px rgba(0, 0, 0, 0.25),
1px 1px 1px rgba(0, 0, 0, 0.25);
}
.team-status-btn-new,
.header-action-btn-new,
.header-view-btn-new {
display: flex;
flex-shrink: 0;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
border: 1.5px solid #1a4d42;
border-radius: 50%;
color: #cef1eb;
cursor: default;
background: linear-gradient(180deg, #0d3f34 0%, #051f19 100%);
box-shadow: 0 0 0 1px #000, 0 2px 2px rgba(0, 0, 0, 0.6);
}
.side-right-actions {
display: flex;
align-items: center;
gap: 12px;
}
.header-stats-bar {
position: absolute;
top: 0;
left: 50%;
z-index: 100;
display: inline-flex;
align-items: center;
height: 40px;
min-height: 40px;
padding: 0 48px;
border-bottom: 1px solid #135643;
border-radius: 0 0 16px 16px;
background: linear-gradient(90deg, #093023 20%, #074833 50%, #093023 80%);
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.2));
transform: translateX(-50%);
}
.header-stats-bar::before,
.header-stats-bar::after {
content: "";
pointer-events: none;
position: absolute;
top: 0;
width: 36px;
height: 30px;
background: transparent;
z-index: 101;
}
.header-stats-bar::before {
left: -35px;
border-top-right-radius: 20px;
box-shadow: 18px 0 #093023;
}
.header-stats-bar::after {
right: -35px;
border-top-left-radius: 20px;
box-shadow: -18px 0 #093023;
}
.poly-stat-item {
display: flex;
align-items: center;
gap: 8px;
font-size: 18px;
font-weight: 400;
letter-spacing: -0.3px;
white-space: nowrap;
color: #eeeae3;
}
.header-stat-text {
text-shadow:
-1px -1px 0 #00000040,
1px -1px 0 #00000040,
-1px 1px 0 #00000040,
1px 1px 0 #00000040;
}
.poly-stat-quarter { font-weight: 600; color: #ffffffc4; }
.poly-stat-bullet { color: rgba(238, 234, 227, 0.4); }
.poly-stat-divider {
flex-shrink: 0;
width: 1px;
height: 16px;
margin: 0 4px;
background-color: rgba(238, 234, 227, 0.4);
}
.poly-click-stat {
display: inline;
padding: 2px 6px;
border-radius: 4px;
line-height: 21px;
color: #fffc;
font-size: 18px;
border: 1px solid #1d6947;
background: linear-gradient(180deg, #337c5f 0%, #1c4638 100%);
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.3);
}
.poly-click-stat.active {
background: linear-gradient(
180deg,
rgba(0, 0, 0, 0.54) 0%,
rgba(0, 0, 0, 0.25) 20%,
rgba(0, 0, 0, 0.09) 80%,
rgba(0, 0, 0, 0.54) 100%
);
border: 1px solid rgba(0, 0, 0, 0.86);
box-shadow: inset 0 0 2px rgba(0, 0, 0, 0.3);
}
.poly-stat-val { font-weight: 800; }
.poly-stat-unit { font-size: 14px; font-weight: 500; opacity: 0.5; }
.stat-yellow { color: #ffdb3a; }
.stat-green { color: #10b981; }
.stat-orange { color: #ff9f0a; }
.stat-gray { color: #b0b0b0; }
.stat-red { color: #ff5252; }
.dual-monitor-icon-wrap {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 16px;
height: 16px;
}
.dual-monitor-icon-wrap svg {
position: absolute;
stroke: currentColor;
fill: none;
stroke-width: 2;
stroke-linecap: round;
stroke-linejoin: round;
}
.dual-monitor-icon-wrap .m-back { top: 0; left: -3px; opacity: 0.5; width: 12px; height: 12px; }
.dual-monitor-icon-wrap .m-front { right: -3px; bottom: 0; width: 12px; height: 12px; }
/* ─── 본문 ─── */
.page-content {
flex: 1;
min-height: 0;
display: flex;
flex-direction: column;
overflow: hidden;
padding: 12px 16px 14px;
background: var(--page-bg);
}
.board-layout {
position: relative;
flex: 1;
min-height: 0;
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(320px, 360px) minmax(0, 1fr);
grid-template-rows: 1fr 1fr;
gap: 12px 24px;
width: 100%;
align-items: stretch;
}
.connectors {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 2;
overflow: visible;
}
.connectors path,
.connectors line {
fill: none;
stroke-linecap: butt;
stroke-linejoin: miter;
vector-effect: non-scaling-stroke;
}
/*
* ─── [BACKUP] 부문 카드 — A안 적용 전 (2026-06-08) ───
* 되돌리려면 아래 A안 블록을 지우고 BACKUP 주석을 해제하세요.
*
* .dept-card { border-radius:16px; border:1.5px solid var(--card-border);
* padding:16px 18px 14px; background:var(--card-bg); box-shadow:var(--card-shadow); }
* .dept-icon { display:flex; width:40px; height:40px; border-radius:50%; … filled circle }
* .dept-head { margin-bottom:10px; padding-bottom:10px; border-bottom:2px solid;
* background:none; align-items:flex-end; }
* .project-sub-card { border-radius:12px; padding:12px 14px;
* border:1px solid #e2e8ef; background:#f7f9fb; }
* .project-sub-card--hrm { background:var(--hrm-soft); border-color:#c8dfd5; } …
* .board-project-list { gap:10px; padding:4px 0 0; }
*
* ─── [BACKUP-A] A안 헤더 — 강화 적용 전 (2026-06-08) ───
* 헤더 강화만 되돌릴 때: BACKUP-A 블록으로 .dept-card / .dept-head / accent 규칙 복원
*
* .dept-card { border:1px solid #c8dfd5; (border-top-width 1px, top-color #c8dfd5) }
* .dept-head { padding:14px 18px 10px; border-bottom:3px solid var(--dept);
* margin-bottom:0; (no ::after, no #c5d9cc hairline) }
* .dept-card--hrm .dept-head { border-bottom-color:var(--hrm); } …
*
* ─── [BACKUP-B] 헤더 강화 (상단+이중 underline) — 되돌림 (2026-06-08) ───
* .dept-card { border-top-width:3px; border-top-color:var(--dept); }
* .dept-head { padding:14px 20px 10px; border-bottom:1px solid #c5d9cc;
* margin-bottom:3px; } + .dept-head::after { height:3px; bottom:-3px; }
*
* ─── [BACKUP-C] 부서별 4색 accent — B안 적용 전 (2026-06-08) ───
* .dept-card--* .dept-head { border-bottom-color:var(--hrm|hrd|ex|ga); }
* .board-dept-title--* / .board-dept-title-en--* / .dept-head-count--* /
* .project-sub-card--* .project-field-label { color: var(--dept); }
* .donut { --color: var(--hrm|hrd|ex|ga); } (inline)
*
* ─── [BACKUP-D] mint 보드형 (A+B) — 데스크/종이 테마 적용 전 (2026-06-08) ───
* .dept-card { border-radius:12px; border:1px solid #c8dfd5; background:#f8fcfa;
* box-shadow:none; }
* .dept-head { border-bottom:3px solid var(--dept-accent);
* background:linear-gradient(180deg,#f8fcfa 0%,#f0f7f4 100%); }
* .board-project-list { background:#f8fcfa; }
* .project-sub-card { border-bottom:1px solid #dce8e3; }
* .project-sub-card:hover { background:linear-gradient(180deg,#f2f9f6,#eaf3ef); }
* .project-field-label { color:var(--dept-accent); }
* .donut::after { background:#f8fcfa; }
*/
/* ─── 부문 카드 — 데스크/게시판 (sage 종이 · 포스트잇·플래너와 동일 재질) ─── */
.dept-card {
position: relative;
z-index: 3;
height: 100%;
min-height: 0;
display: flex;
flex-direction: column;
border-radius: 6px;
border: 1px solid rgba(41, 114, 79, 0.1);
padding: 0;
background: linear-gradient(168deg, #f9fbf9 0%, #f5faf8 100%);
box-shadow:
0 3px 12px rgba(15, 35, 52, 0.06),
0 1px 3px rgba(22, 72, 52, 0.04);
overflow: hidden;
}
.dept-card::before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
height: 1px;
background: rgba(255, 255, 255, 0.55);
pointer-events: none;
z-index: 1;
}
.dept-card--hrm { grid-column: 1; grid-row: 1; }
.dept-card--hrd { grid-column: 3; grid-row: 1; }
.dept-card--ex { grid-column: 1; grid-row: 2; }
.dept-card--ga { grid-column: 3; grid-row: 2; }
/* 아이콘 숨김 (HTML은 BACKUP용으로 유지) */
.dept-icon {
display: none;
}
.dept-head {
position: relative;
z-index: 2;
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
margin-bottom: 0;
padding: 16px 16px 10px;
border-bottom: 1px solid #d8e8e0;
background: linear-gradient(180deg, #fcfefd 0%, #f7fbf9 100%);
flex-shrink: 0;
}
.dept-head-main {
display: flex;
align-items: baseline;
gap: 0;
min-width: 0;
flex: 1;
}
.dept-head-count {
display: inline-flex;
align-items: baseline;
flex-shrink: 0;
font-size: 28px;
font-weight: 400;
letter-spacing: -0.4px;
line-height: 1;
white-space: nowrap;
}
.dept-head-count .poly-stat-val {
font-weight: 800;
font-size: 28px;
line-height: 1;
}
.dept-head-count .poly-stat-unit {
font-size: 13px;
font-weight: 600;
opacity: 0.55;
}
.dept-card .board-dept-title {
color: #0a2e24;
}
.dept-card .dept-head-count .poly-stat-val,
.dept-card .dept-head-count .poly-stat-unit,
.dept-card .board-dept-title-en {
color: var(--dept-accent);
}
.board-dept-header-main {
min-width: 0;
flex: 1;
}
.board-dept-title-wrap {
display: flex;
align-items: baseline;
gap: 8px;
min-width: 0;
flex: 1;
}
.board-dept-title {
margin: 0;
font-size: 28px;
font-weight: 800;
letter-spacing: -0.6px;
line-height: 1;
}
.board-dept-title-en {
font-size: 19px;
font-weight: 700;
letter-spacing: 0.1px;
line-height: 1;
flex-shrink: 0;
opacity: 0.85;
}
/* ─── 프로젝트 목록 — 종이 메모 리스트 ─── */
.board-project-list {
min-height: 0;
flex: 1;
display: flex;
flex-direction: column;
gap: 0;
overflow-y: auto;
padding: 8px 14px 10px;
background: transparent;
}
.project-sub-card {
border-radius: 0;
padding: 10px 2px 12px;
border: none;
border-bottom: 1px dashed #c8d9d0;
background: rgba(255, 255, 255, 0.38);
flex-shrink: 0;
transition: background 0.2s ease;
}
.project-sub-card:last-child {
border-bottom: none;
}
.project-sub-card:hover {
background: linear-gradient(168deg, #eef6f2 0%, #e4efe9 100%);
}
.project-sub-body {
display: grid;
grid-template-columns: 1fr auto;
gap: 14px;
align-items: center;
}
.project-fields {
display: flex;
flex-direction: column;
gap: 7px;
min-width: 0;
}
.project-field {
display: grid;
grid-template-columns: 96px 1fr;
gap: 8px;
align-items: baseline;
}
.project-sub-title {
font-size: 24px;
font-weight: 600;
color: #0a2e24;
line-height: 1.35;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
.project-field-label {
font-size: 20px;
font-weight: 600;
line-height: 1.45;
color: #5a6b62;
}
.project-field .project-field-value {
font-size: 20px;
font-weight: 500;
color: #5a6b62;
line-height: 1.45;
}
.project-field-value {
font-family: inherit;
overflow: hidden;
text-overflow: ellipsis;
}
.project-sub-divider {
display: none;
}
.progress-col {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
flex-shrink: 0;
width: 93px;
}
.dept-card .donut {
--color: var(--dept-accent);
background: conic-gradient(var(--color) calc(var(--pct) * 1%), #d4ddd8 0);
}
.donut {
--pct: 0;
--color: #29724f;
position: relative;
width: 93px;
height: 93px;
border-radius: 50%;
background: conic-gradient(var(--color) calc(var(--pct) * 1%), #dde4ec 0);
}
.donut::after {
content: "";
position: absolute;
inset: 12px;
border-radius: 50%;
background: #f4f9f6;
}
.project-sub-card:hover .donut::after {
background: #eef6f2;
}
.donut span {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
z-index: 1;
font-size: 21px;
font-weight: 800;
color: var(--color);
}
/*
* ─── 중앙 허브 — 단일 컬럼 flex (슬로건·다이아·일정 비율 고정)
*/
.hub-column {
grid-column: 2;
grid-row: 1 / 3;
display: grid;
grid-template-rows: var(--hub-slogan-band-h) 1fr var(--hub-slogan-band-h);
align-content: stretch;
min-height: 0;
min-width: 0;
width: 100%;
z-index: 2;
--hub-row-h: calc((100% - 12px) / 2);
--hub-band-h: min(calc(var(--hub-row-h) * 0.52), 188px);
--hub-slogan-band-h: min(calc(var(--hub-row-h) * 0.624), 226px);
/* 일정: 박스 top → 제목 (플래너·헤더 띠에서 역산) */
--hub-title-top: 20px;
/* 슬로건: 바깥(그리드→포스트잇) + 안(핀 아래→제목). 일정 플래너 14px과 같은 호흡 */
--hub-slogan-pad-top: 16px;
--hub-slogan-postit-pad-top: 14px;
/* 일정: 헤더 띠 + 플래너 (플래너 padding-top도 title-top에서 역산) */
--hub-head-offset-top: -2px;
--hub-head-pad-top: 8px;
--hub-head-pad-bottom: 7px;
--hub-card-pad-x: 12px;
--hub-card-pad-bottom: 10px;
--hub-diamond-scale: 0.9;
}
.hub-box--message {
grid-row: 1;
align-self: stretch;
height: 100%;
min-height: 0;
z-index: 3;
}
.hub-box--focus {
grid-row: 3;
align-self: stretch;
height: 100%;
min-height: 0;
z-index: 3;
}
.hub-diamond-wrap {
grid-row: 2;
min-height: 0;
align-self: stretch;
z-index: 1;
}
.hub-box {
position: relative;
z-index: 3;
width: 100%;
background: var(--card-bg);
border: 1.5px solid var(--hub-border);
border-radius: 14px;
padding: 12px 16px;
box-shadow: var(--card-shadow);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 6px;
min-height: 0;
text-align: center;
}
.hub-box-title-row {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 6px;
margin-bottom: 4px;
}
.hub-box-icon {
width: 28px;
height: 28px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
flex-shrink: 0;
background: #eef2f6;
border: 1px solid #d8e2ea;
}
/* 분기 슬로건 — 2장 겹친 sage 포스트잇 */
.hub-box--message {
background: transparent;
border: none;
box-shadow: none;
padding: var(--hub-slogan-pad-top) 0 0;
overflow: visible;
width: 100%;
box-sizing: border-box;
display: flex;
flex-direction: column;
flex-shrink: 0;
}
.hub-box--message .hub-postit-stack {
flex: 1 1 auto;
min-height: 0;
height: auto;
}
.hub-box--message .hub-postit-sheet--front {
height: 100%;
min-height: 0;
display: flex;
flex-direction: column;
padding:
var(--hub-slogan-postit-pad-top)
14px
8px;
gap: 0;
justify-content: flex-start;
}
.hub-box--message .hub-postit-content {
flex: 1 1 auto;
min-height: 0;
gap: 0;
justify-content: flex-start;
align-items: center;
width: 100%;
}
.hub-box--message .hub-postit-header {
width: 100%;
margin: 0;
padding-top: 0;
padding-bottom: 6px;
background: none;
border-bottom: 1px solid #c5d9cc;
border-radius: 0;
flex-shrink: 0;
}
.hub-box--message .hub-postit-message {
gap: 2px;
flex: 1 1 auto;
min-height: 0;
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.hub-postit-stack {
position: relative;
width: 100%;
height: auto;
min-height: 0;
overflow: visible;
}
.hub-postit-sheet--back {
position: absolute;
top: 1px;
left: -3px;
right: 3px;
bottom: 3px;
transform: rotate(-1.5deg);
background: linear-gradient(168deg, #cddfd7 0%, #bfd5cb 100%);
border: 1px solid var(--postit-border);
border-radius: 4px;
box-shadow: 0 3px 10px rgba(22, 72, 52, 0.09);
z-index: 0;
pointer-events: none;
}
.hub-postit-sheet--front {
position: relative;
z-index: 2;
width: 100%;
height: auto;
min-height: 0;
padding: 12px 14px 10px;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
gap: 5px;
background: linear-gradient(168deg, var(--postit-bg) 0%, var(--postit-bg-deep) 100%);
border: 1px solid var(--postit-border);
border-radius: 4px;
box-shadow: var(--postit-shadow);
overflow: visible;
}
.hub-postit-sheet--front::before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
height: 1px;
background: rgba(255, 255, 255, 0.55);
pointer-events: none;
}
.hub-postit-content {
position: relative;
z-index: 2;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
gap: 6px;
width: 100%;
flex: 0 0 auto;
min-height: 0;
padding-top: 0;
}
.hub-postit-header {
width: 100%;
display: flex;
justify-content: center;
padding-top: 4px;
padding-bottom: 6px;
border-bottom: 1px solid #c5d9cc;
flex-shrink: 0;
}
.hub-postit-message {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 2px;
width: 100%;
flex: 0 0 auto;
min-height: 0;
}
.hub-postit-message .board-project-desc {
margin: 0;
text-align: center;
line-height: 1.45;
}
.hub-postit-dept-line {
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
flex-wrap: wrap;
}
/* 오른쪽 하단 접힘 */
.hub-postit-fold {
position: absolute;
right: 0;
bottom: 0;
width: 28px;
height: 28px;
z-index: 4;
pointer-events: none;
}
.hub-postit-fold::before {
content: "";
position: absolute;
right: 0;
bottom: 0;
width: 28px;
height: 28px;
background: linear-gradient(315deg, #edf5f1 0%, #d2e6dc 45%, #bdd8cc 100%);
clip-path: polygon(100% 0, 0 100%, 100% 100%);
box-shadow: -2px -2px 5px rgba(15, 35, 52, 0.1);
}
.hub-postit-fold::after {
content: "";
position: absolute;
right: 3px;
bottom: 3px;
width: 22px;
height: 22px;
background: rgba(15, 35, 52, 0.1);
clip-path: polygon(100% 0, 0 100%, 100% 100%);
filter: blur(1px);
z-index: -1;
}
/* 빨간 원형 핀 */
.hub-postit-pin {
position: absolute;
top: -9px;
left: 50%;
width: 20px;
height: 24px;
z-index: 6;
pointer-events: none;
transform: translateX(-50%);
filter: drop-shadow(0 3px 4px rgba(90, 20, 20, 0.24));
}
.hub-postit-pin::before {
content: "";
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%);
width: 18px;
height: 18px;
border-radius: 50%;
background:
radial-gradient(circle at 28% 22%, rgba(255, 255, 255, 0.92) 0%, rgba(255, 255, 255, 0.22) 16%, transparent 38%),
radial-gradient(circle at 72% 74%, rgba(70, 10, 10, 0.38) 0%, transparent 52%),
radial-gradient(circle at 50% 58%, #e86565 0%, #cc4545 42%, #a83232 72%, #7a2222 100%);
box-shadow:
0 4px 7px rgba(90, 20, 20, 0.32),
0 1px 2px rgba(0, 0, 0, 0.18),
inset 0 -4px 7px rgba(70, 10, 10, 0.42),
inset 0 3px 5px rgba(255, 210, 210, 0.28);
}
.hub-postit-pin::after {
content: "";
position: absolute;
top: 15px;
left: 50%;
transform: translateX(-50%);
width: 2px;
height: 7px;
border-radius: 0 0 1px 1px;
background: linear-gradient(180deg, #c8c8c8 0%, #949494 45%, #6e6e6e 100%);
box-shadow:
0 5px 4px -1px rgba(15, 35, 52, 0.2),
0 0 0 3px rgba(15, 35, 52, 0.07),
1px 0 0 rgba(255, 255, 255, 0.35);
}
.hub-box--message .hub-box-title-row {
flex-direction: row;
align-items: center;
justify-content: center;
gap: 8px;
margin-bottom: 2px;
}
.hub-message-icon {
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
line-height: 0;
}
.hub-message-icon svg {
width: 22px;
height: 22px;
stroke: var(--hrm);
fill: none;
stroke-width: 2.4;
stroke-linecap: round;
stroke-linejoin: round;
}
.hub-box--message .hub-box-title-row .board-project-title {
text-align: center;
}
/* ─── 대시보드 본문 타이포 — 프로젝트 카드 · 허브 공통 ─── */
.board-project-title {
margin: 0;
color: #0a2e24;
font-size: 24px;
font-weight: 600;
line-height: 1.35;
font-family: inherit;
}
.board-project-desc {
margin: 0;
color: #5a6b62;
font-size: 20px;
font-weight: 500;
line-height: 1.45;
font-family: inherit;
}
/* 허브 3구역 — project-sub-title / project-field-value 와 동일 */
.hub-column .board-project-title {
font-size: 24px;
font-weight: 600;
line-height: 1.35;
color: #0a2e24;
}
.hub-column .board-project-desc,
.hub-column .hub-routine-item {
font-size: 20px;
font-weight: 500;
line-height: 1.45;
font-family: inherit;
}
.hub-column .hub-schedule-month {
font-size: 20px;
font-weight: 600;
line-height: 1.45;
color: #5a6b62;
}
.hub-box .board-project-title,
.hub-box .board-project-desc {
text-align: center;
}
.hub-list .board-project-desc {
padding: 1px 0;
text-align: center;
}
.hub-list {
list-style: none;
text-align: center;
padding: 0;
width: 100%;
}
.hub-box--focus {
background: transparent;
border: none;
box-shadow: none;
padding: 0 0 2px;
overflow: visible;
min-height: 0;
width: 100%;
box-sizing: border-box;
display: flex;
flex-direction: column;
flex-shrink: 0;
}
.hub-box--focus .hub-schedule-planner {
flex: 1 1 auto;
height: 100%;
min-height: 0;
justify-content: flex-start;
}
.hub-box--focus .hub-schedule-head {
flex-shrink: 0;
}
.hub-box--focus .hub-schedule-list {
flex: 1 1 auto;
min-height: 0;
justify-content: center;
padding: 0;
}
.hub-schedule-planner {
position: relative;
width: 100%;
height: auto;
min-height: 0;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
gap: 6px;
padding:
calc(var(--hub-title-top) - var(--hub-head-pad-top) - var(--hub-head-offset-top))
var(--hub-card-pad-x)
var(--hub-card-pad-bottom);
background: linear-gradient(180deg, #faf8f3 0%, #f2ece3 100%);
border: 1px solid #ddd5c8;
border-radius: 6px;
box-shadow: 0 3px 12px rgba(15, 35, 52, 0.08);
overflow: visible;
}
.hub-schedule-planner::before {
content: "";
position: absolute;
top: 5px;
left: 50%;
transform: translateX(-50%);
width: 52px;
height: 5px;
background: radial-gradient(circle, #bdb5a8 1.5px, transparent 1.5px) center / 13px 100% repeat-x;
opacity: 0.5;
pointer-events: none;
}
.hub-schedule-head {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
width: calc(100% + var(--hub-card-pad-x) * 2);
margin: var(--hub-head-offset-top) calc(-1 * var(--hub-card-pad-x)) 0;
padding: var(--hub-head-pad-top) var(--hub-card-pad-x) var(--hub-head-pad-bottom);
background: linear-gradient(180deg, #f6f0e6 0%, #efe8dc 100%);
border-bottom: 1px solid #e4ddd2;
border-radius: 5px 5px 0 0;
}
.hub-schedule-head .board-project-title {
text-align: center;
}
.hub-schedule-icon {
display: flex;
align-items: center;
flex-shrink: 0;
line-height: 0;
}
.hub-schedule-icon svg {
width: 22px;
height: 22px;
stroke: #8f8578;
fill: none;
stroke-width: 2.4;
stroke-linecap: round;
stroke-linejoin: round;
}
.hub-schedule-list {
list-style: none;
margin: 0;
padding: 4px 0 2px;
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 3px;
flex: 0 0 auto;
min-height: 0;
}
.hub-schedule-item {
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
width: 100%;
max-width: 100%;
padding: 4px 0;
border-bottom: 1px dashed #e8e0d4;
}
.hub-schedule-item:last-child {
border-bottom: none;
}
.hub-schedule-month {
flex-shrink: 0;
text-align: center;
}
.hub-schedule-item .board-project-desc {
margin: 0;
text-align: center;
line-height: 1.45;
flex: 0 1 auto;
}
.hub-box--focus .hub-list li::before {
content: none;
}
.hub-diamond-wrap {
z-index: 1;
min-height: 0;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
padding: 0;
overflow: visible;
pointer-events: none;
box-sizing: border-box;
}
.hub-diamond-wrap > * {
pointer-events: auto;
}
.hub-diamond-icon {
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
line-height: 0;
}
.hub-diamond-icon svg {
width: 22px;
height: 22px;
stroke: #6eecc8;
fill: none;
stroke-width: 2.4;
stroke-linecap: round;
stroke-linejoin: round;
}
.hub-diamond {
flex-shrink: 0;
transform: rotate(45deg);
background: var(--hub-diamond-bg);
border: 2.5px solid var(--hub-diamond-border);
border-radius: 10px;
box-shadow: 0 6px 22px rgba(7, 65, 46, 0.28);
display: flex;
align-items: center;
justify-content: center;
}
.hub-diamond-inner {
transform: rotate(-45deg);
width: 92%;
max-height: 92%;
text-align: center;
padding: 0 8px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 4px;
overflow: hidden;
}
.hub-diamond-head {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
width: 100%;
}
.hub-diamond-head .board-project-title {
text-align: left;
color: #fff;
margin: 0;
font-size: 24px;
font-weight: 600;
line-height: 1.35;
}
.hub-diamond-divider {
width: 88%;
height: 1px;
background: rgba(255, 255, 255, 0.22);
margin: 2px 0 4px;
flex-shrink: 0;
}
.hub-routine-grid {
display: grid;
grid-template-columns: 1fr 1fr;
column-gap: 10px;
row-gap: 2px;
width: 100%;
max-width: 100%;
justify-items: center;
}
.hub-routine-item {
appearance: none;
background: none;
border: none;
padding: 2px 4px;
margin: 0;
color: #8fd4bc;
cursor: pointer;
border-radius: 4px;
transition: color 0.18s ease, opacity 0.18s ease, text-shadow 0.18s ease;
}
.hub-routine-item:hover {
color: #b4ecd6;
text-shadow: 0 0 10px rgba(143, 212, 188, 0.28);
}
.hub-routine-item:active {
opacity: 0.82;
}
.hub-routine-item:focus-visible {
outline: 1px solid rgba(143, 212, 188, 0.45);
outline-offset: 2px;
}
@media (max-width: 1200px) {
.page-content {
overflow: auto;
}
.board-layout {
grid-template-columns: 1fr;
grid-template-rows: auto;
flex: none;
}
.connectors { display: none; }
.dept-card--hrm, .dept-card--hrd, .dept-card--ex, .dept-card--ga {
grid-column: 1;
grid-row: auto;
}
.hub-column {
grid-column: 1;
grid-row: auto;
order: -2;
display: flex;
flex-direction: column;
grid-template-rows: none;
--hub-band-h: none;
--hub-slogan-band-h: none;
}
.hub-box--message,
.hub-box--focus {
grid-row: auto;
max-height: none;
min-height: 0;
height: auto;
}
.hub-box--message { order: -3; }
.hub-diamond-wrap {
grid-row: auto;
order: -2;
flex: 0 0 auto;
height: auto;
min-height: 220px;
}
.hub-box--focus { order: -1; }
}
</style>
</head>
<body class="preview-page">
<!-- 상단바 (기존 DashboardHeader 스타일) -->
<header class="dashboard-header-bar">
<div class="side-left-group">
<span class="main_tit">
<span>총괄기획실</span>
<span>|</span>
<span>People Growth Hub</span>
</span>
<button type="button" class="team-status-btn-new" title="팀 현황" aria-label="팀 현황">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/>
<path d="M16 3.128a4 4 0 0 1 0 7.744"/>
<path d="M22 21v-2a4 4 0 0 0-3-3.87"/>
<circle cx="9" cy="7" r="4"/>
</svg>
</button>
</div>
<div class="header-stats-bar side-polygon-stats">
<div class="poly-stat-item">
<span class="poly-stat-quarter header-stat-text">2026 2분기 업무</span>
<span class="poly-stat-bullet header-stat-text">·</span>
<span class="poly-click-stat active header-stat-text">전체 <span class="poly-stat-val stat-yellow">22</span><span class="poly-stat-unit"></span></span>
<div class="poly-stat-divider" aria-hidden="true"></div>
<span class="poly-click-stat header-stat-text">진행 <span class="poly-stat-val stat-green">16</span><span class="poly-stat-unit"></span></span>
<span class="poly-click-stat header-stat-text">보류 <span class="poly-stat-val stat-orange">4</span><span class="poly-stat-unit"></span></span>
<span class="poly-click-stat header-stat-text">완료 <span class="poly-stat-val stat-gray">2</span><span class="poly-stat-unit"></span></span>
<div class="poly-stat-divider" aria-hidden="true"></div>
<span class="poly-click-stat header-stat-text">이슈 <span class="poly-stat-val stat-red">5</span><span class="poly-stat-unit"></span></span>
</div>
</div>
<div class="side-right-actions">
<button type="button" class="header-action-btn-new" title="신규 프로젝트 추가" aria-label="신규 프로젝트 추가">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M5 12h14"/><path d="M12 5v14"/>
</svg>
</button>
<button type="button" class="header-view-btn-new" title="듀얼뷰" aria-label="듀얼뷰">
<div class="dual-monitor-icon-wrap">
<svg class="m-back" viewBox="0 0 24 24"><rect width="20" height="14" x="2" y="3" rx="2"/><line x1="8" x2="16" y1="21" y2="21"/><line x1="12" x2="12" y1="17" y2="21"/></svg>
<svg class="m-front" viewBox="0 0 24 24"><rect width="20" height="14" x="2" y="3" rx="2"/><line x1="8" x2="16" y1="21" y2="21"/><line x1="12" x2="12" y1="17" y2="21"/></svg>
</div>
</button>
</div>
</header>
<div class="page-content">
<div class="board-layout">
<!-- HRM -->
<section class="dept-card dept-card--hrm">
<div class="dept-head">
<div class="dept-head-main">
<div class="dept-icon dept-icon--hrm">
<svg viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>
</div>
<div class="board-dept-header-main">
<div class="board-dept-title-wrap">
<h2 class="board-dept-title board-dept-title--hrm">인사관리</h2>
<span class="board-dept-title-en board-dept-title-en--hrm">HRM</span>
</div>
</div>
</div>
<div class="dept-head-count dept-head-count--hrm" aria-label="2건">
<span class="poly-stat-val">2</span><span class="poly-stat-unit"></span>
</div>
</div>
<div class="board-project-list">
<article class="project-sub-card project-sub-card--hrm">
<div class="project-sub-body">
<div class="project-fields">
<div class="project-sub-title">상반기 채용 운영</div>
<div class="project-field">
<span class="project-field-label">작업 기간</span>
<span class="project-field-value">2026.04 ~ 2026.06</span>
</div>
<div class="project-field">
<span class="project-field-label">주요 내용</span>
<span class="project-field-value">채용공고, 서류검토, 면접, 사후협의 진행</span>
</div>
</div>
<div class="project-sub-divider" aria-hidden="true"></div>
<div class="progress-col">
<div class="donut" style="--pct:75"><span>75%</span></div>
</div>
</div>
</article>
<article class="project-sub-card project-sub-card--hrm">
<div class="project-sub-body">
<div class="project-fields">
<div class="project-sub-title">평가제도 개선</div>
<div class="project-field">
<span class="project-field-label">작업 기간</span>
<span class="project-field-value">2026.03 ~ 2026.07</span>
</div>
<div class="project-field">
<span class="project-field-label">주요 내용</span>
<span class="project-field-value">평가항목 정비, 부서 의견수렴, 피드백 방식 개선</span>
</div>
</div>
<div class="project-sub-divider" aria-hidden="true"></div>
<div class="progress-col">
<div class="donut" style="--pct:60"><span>60%</span></div>
</div>
</div>
</article>
</div>
</section>
<!-- HRD -->
<section class="dept-card dept-card--hrd">
<div class="dept-head">
<div class="dept-head-main">
<div class="dept-icon dept-icon--hrd">
<svg viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round"><path d="M22 10v6M2 10l10-5 10 5-10 5z"/><path d="M6 12v5c0 1.7 3.3 3 7 3s7-1.3 7-3v-5"/></svg>
</div>
<div class="board-dept-header-main">
<div class="board-dept-title-wrap">
<h2 class="board-dept-title board-dept-title--hrd">인재육성</h2>
<span class="board-dept-title-en board-dept-title-en--hrd">HRD</span>
</div>
</div>
</div>
<div class="dept-head-count dept-head-count--hrd" aria-label="2건">
<span class="poly-stat-val">2</span><span class="poly-stat-unit"></span>
</div>
</div>
<div class="board-project-list">
<article class="project-sub-card project-sub-card--hrd">
<div class="project-sub-body">
<div class="project-fields">
<div class="project-sub-title">신규입사자 온보딩 프로그램</div>
<div class="project-field">
<span class="project-field-label">작업 기간</span>
<span class="project-field-value">2026.04 ~ 2026.06</span>
</div>
<div class="project-field">
<span class="project-field-label">주요 내용</span>
<span class="project-field-value">신규입사자 교육, 조직 적응 프로그램 운영</span>
</div>
</div>
<div class="project-sub-divider" aria-hidden="true"></div>
<div class="progress-col">
<div class="donut" style="--pct:85"><span>85%</span></div>
</div>
</div>
</article>
<article class="project-sub-card project-sub-card--hrd">
<div class="project-sub-body">
<div class="project-fields">
<div class="project-sub-title">팀장 리더십 교육</div>
<div class="project-field">
<span class="project-field-label">작업 기간</span>
<span class="project-field-value">2026.05 ~ 2026.06</span>
</div>
<div class="project-field">
<span class="project-field-label">주요 내용</span>
<span class="project-field-value">팀장 대상 리더십·코칭·피드백 교육 실시</span>
</div>
</div>
<div class="project-sub-divider" aria-hidden="true"></div>
<div class="progress-col">
<div class="donut" style="--pct:100"><span>100%</span></div>
</div>
</div>
</article>
</div>
</section>
<!-- 중앙 허브 -->
<div class="hub-column" id="hub-column">
<!-- 분기 슬로건 -->
<div class="hub-box hub-box--message">
<div class="hub-postit-stack">
<div class="hub-postit-sheet hub-postit-sheet--back" aria-hidden="true"></div>
<div class="hub-postit-sheet hub-postit-sheet--front">
<span class="hub-postit-pin" aria-hidden="true"></span>
<span class="hub-postit-fold" aria-hidden="true"></span>
<div class="hub-postit-content">
<div class="hub-postit-header">
<div class="hub-box-title-row">
<span class="hub-message-icon" aria-hidden="true">
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M12 4v5"/>
<path d="M12 15v5"/>
<path d="M4 12h5"/>
<path d="M15 12h5"/>
<path d="M18 5v2"/>
<path d="M17 6h2"/>
<path d="M5 17v2"/>
<path d="M4 18h2"/>
</svg>
</span>
<div class="board-project-title">분기 슬로건</div>
</div>
</div>
<div class="hub-postit-message">
<p class="board-project-desc hub-postit-dept-line">
<span>인사</span><span>육성</span><span>문화</span><span>총무</span>
</p>
<p class="board-project-desc">개선과제</p>
<p class="board-project-desc">정상 추진</p>
</div>
</div>
</div>
</div>
</div>
<!-- 상시업무 -->
<div class="hub-diamond-wrap" id="hub-diamond-wrap">
<div class="hub-diamond" id="hub-diamond">
<div class="hub-diamond-inner">
<div class="hub-diamond-head">
<span class="hub-diamond-icon" aria-hidden="true">
<svg viewBox="0 0 24 24"><path d="m17 2 4 4-4 4"/><path d="M3 11v-1a4 4 0 0 1 4-4h14"/><path d="m7 22-4-4 4-4"/><path d="M21 13v1a4 4 0 0 1-4 4H3"/></svg>
</span>
<div class="board-project-title">상시업무</div>
</div>
<div class="hub-diamond-divider" aria-hidden="true"></div>
<div class="hub-routine-grid">
<button type="button" class="hub-routine-item">채용</button>
<button type="button" class="hub-routine-item">교육</button>
<button type="button" class="hub-routine-item">소통</button>
<button type="button" class="hub-routine-item">시설</button>
<button type="button" class="hub-routine-item">자산</button>
<button type="button" class="hub-routine-item">행정</button>
</div>
</div>
</div>
</div>
<!-- 분기 주요 일정 -->
<div class="hub-box hub-box--focus">
<div class="hub-schedule-planner">
<div class="hub-schedule-head">
<span class="hub-schedule-icon" aria-hidden="true">
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M8 2v4"/>
<path d="M16 2v4"/>
<rect x="3" y="4" width="18" height="18" rx="2"/>
<path d="M3 10h18"/>
<path d="M8 14v.01"/>
<path d="M12 14v.01"/>
<path d="M16 14v.01"/>
</svg>
</span>
<div class="board-project-title">분기 주요 일정</div>
</div>
<ul class="hub-schedule-list">
<li class="hub-schedule-item">
<span class="hub-schedule-month">4월</span>
<span class="board-project-desc">평가제도 시행</span>
</li>
<li class="hub-schedule-item">
<span class="hub-schedule-month">5월</span>
<span class="board-project-desc">상반기 채용 마감</span>
</li>
<li class="hub-schedule-item">
<span class="hub-schedule-month">6월</span>
<span class="board-project-desc">복지·안전 점검</span>
</li>
</ul>
</div>
</div>
</div>
<!-- EX -->
<section class="dept-card dept-card--ex">
<div class="dept-head">
<div class="dept-head-main">
<div class="dept-icon dept-icon--ex">
<svg viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round"><path d="M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.29 1.51 4.04 3 5.5l7 7Z"/></svg>
</div>
<div class="board-dept-header-main">
<div class="board-dept-title-wrap">
<h2 class="board-dept-title board-dept-title--ex">조직문화</h2>
<span class="board-dept-title-en board-dept-title-en--ex">EX</span>
</div>
</div>
</div>
<div class="dept-head-count dept-head-count--ex" aria-label="2건">
<span class="poly-stat-val">2</span><span class="poly-stat-unit"></span>
</div>
</div>
<div class="board-project-list">
<article class="project-sub-card project-sub-card--ex">
<div class="project-sub-body">
<div class="project-fields">
<div class="project-sub-title">조직문화 진단</div>
<div class="project-field">
<span class="project-field-label">작업 기간</span>
<span class="project-field-value">2026.04 ~ 2026.05</span>
</div>
<div class="project-field">
<span class="project-field-label">주요 내용</span>
<span class="project-field-value">만족도 조사, 직원 의견수렴, 개선과제 도출</span>
</div>
</div>
<div class="project-sub-divider" aria-hidden="true"></div>
<div class="progress-col">
<div class="donut" style="--pct:100"><span>100%</span></div>
</div>
</div>
</article>
<article class="project-sub-card project-sub-card--ex">
<div class="project-sub-body">
<div class="project-fields">
<div class="project-sub-title">복리후생제도 개선</div>
<div class="project-field">
<span class="project-field-label">작업 기간</span>
<span class="project-field-value">2026.05 ~ 2026.08</span>
</div>
<div class="project-field">
<span class="project-field-label">주요 내용</span>
<span class="project-field-value">복지제도 이용현황 분석, 개선안 검토</span>
</div>
</div>
<div class="project-sub-divider" aria-hidden="true"></div>
<div class="progress-col">
<div class="donut" style="--pct:50"><span>50%</span></div>
</div>
</div>
</article>
</div>
</section>
<!-- GA -->
<section class="dept-card dept-card--ga">
<div class="dept-head">
<div class="dept-head-main">
<div class="dept-icon dept-icon--ga">
<svg viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round"><rect width="16" height="20" x="4" y="2" rx="2" ry="2"/><path d="M9 22v-4h6v4"/><path d="M8 6h.01"/><path d="M16 6h.01"/><path d="M12 6h.01"/><path d="M12 10h.01"/><path d="M12 14h.01"/><path d="M16 10h.01"/><path d="M16 14h.01"/><path d="M8 10h.01"/><path d="M8 14h.01"/></svg>
</div>
<div class="board-dept-header-main">
<div class="board-dept-title-wrap">
<h2 class="board-dept-title board-dept-title--ga">총무관리</h2>
<span class="board-dept-title-en board-dept-title-en--ga">GA</span>
</div>
</div>
</div>
<div class="dept-head-count dept-head-count--ga" aria-label="2건">
<span class="poly-stat-val">2</span><span class="poly-stat-unit"></span>
</div>
</div>
<div class="board-project-list">
<article class="project-sub-card project-sub-card--ga">
<div class="project-sub-body">
<div class="project-fields">
<div class="project-sub-title">사무공간 재배치</div>
<div class="project-field">
<span class="project-field-label">작업 기간</span>
<span class="project-field-value">2026.04 ~ 2026.07</span>
</div>
<div class="project-field">
<span class="project-field-label">주요 내용</span>
<span class="project-field-value">좌석 재배치, 회의실 운영 개선</span>
</div>
</div>
<div class="project-sub-divider" aria-hidden="true"></div>
<div class="progress-col">
<div class="donut" style="--pct:70"><span>70%</span></div>
</div>
</div>
</article>
<article class="project-sub-card project-sub-card--ga">
<div class="project-sub-body">
<div class="project-fields">
<div class="project-sub-title">안전·보안 점검 강화</div>
<div class="project-field">
<span class="project-field-label">작업 기간</span>
<span class="project-field-value">2026.04 ~ 2026.06</span>
</div>
<div class="project-field">
<span class="project-field-label">주요 내용</span>
<span class="project-field-value">출입통제, 보안카드, 시설안전, 소방점검 관리</span>
</div>
</div>
<div class="project-sub-divider" aria-hidden="true"></div>
<div class="progress-col">
<div class="donut" style="--pct:85"><span>85%</span></div>
</div>
</div>
</article>
</div>
</section>
<!-- 연결선: JS — 다이아몬드 ↔ 4부문 카드 (꺾임) -->
<svg class="connectors" aria-hidden="true">
<g id="connector-lines"></g>
</svg>
</div>
</div>
<script>
(function () {
var SVG_NS = 'http://www.w3.org/2000/svg';
function relBox(el, parent) {
var r = el.getBoundingClientRect();
var p = parent.getBoundingClientRect();
return {
left: r.left - p.left,
top: r.top - p.top,
right: r.right - p.left,
bottom: r.bottom - p.top,
cx: r.left - p.left + r.width / 2,
cy: r.top - p.top + r.height / 2,
width: r.width,
height: r.height,
};
}
function diamondVertex(cx, cy, size, vertex) {
var r = size / Math.SQRT2;
if (vertex === 'top') return { x: cx, y: cy - r };
if (vertex === 'right') return { x: cx + r, y: cy };
if (vertex === 'bottom') return { x: cx, y: cy + r };
return { x: cx - r, y: cy };
}
function diamondEdgeMidpoint(cx, cy, size, edge) {
var d = size / (2 * Math.SQRT2);
if (edge === 'top-left') return { x: cx - d, y: cy - d };
if (edge === 'top-right') return { x: cx + d, y: cy - d };
if (edge === 'bottom-left') return { x: cx - d, y: cy + d };
return { x: cx + d, y: cy + d };
}
function cardEdgeAnchor(cardEl, layout, side, y) {
var cardBox = relBox(cardEl, layout);
y = Math.max(cardBox.top + 10, Math.min(cardBox.bottom - 10, y));
return {
x: side === 'right' ? cardBox.right : cardBox.left,
y: y,
};
}
var FACE_LINKS = [
{ edge: 'top-left', card: '.dept-card--hrm', side: 'right', vert: 'top', knee: 'left' },
{ edge: 'top-right', card: '.dept-card--hrd', side: 'left', vert: 'top', knee: 'right' },
{ edge: 'bottom-left', card: '.dept-card--ex', side: 'right', vert: 'bottom', knee: 'left' },
{ edge: 'bottom-right', card: '.dept-card--ga', side: 'left', vert: 'bottom', knee: 'right' },
];
function buildBentPath(cardAnchor, edgeMid, side, kneeX, approachX) {
var C = cardAnchor;
var M = edgeMid;
var minLeg = 18;
var x1 = kneeX;
if (side === 'right') {
if (x1 < C.x + minLeg) x1 = C.x + minLeg;
return [C, { x: x1, y: C.y }, { x: approachX, y: M.y }, M];
}
if (x1 > C.x - minLeg) x1 = C.x - minLeg;
return [C, { x: x1, y: C.y }, { x: approachX, y: M.y }, M];
}
function anchorYForSymmetricFace(cy, faceY, runX, vert) {
return vert === 'top' ? faceY + runX : faceY - runX;
}
function appendPath(lineGroup, points) {
var path = document.createElementNS(SVG_NS, 'path');
path.setAttribute('d', pointsToPath(points));
path.setAttribute('stroke', '#b0bcc8');
path.setAttribute('stroke-width', '2.5');
path.setAttribute('opacity', '0.85');
path.setAttribute('fill', 'none');
lineGroup.appendChild(path);
}
function drawPolyline(lineGroup, points) {
appendPath(lineGroup, points);
}
function snap(n) {
return Math.round(n * 2) / 2;
}
function pointsToPath(points) {
return points.map(function (p, i) {
return (i === 0 ? 'M' : 'L') + snap(p.x).toFixed(1) + ' ' + snap(p.y).toFixed(1);
}).join(' ');
}
function hubColumnBox(layout) {
var col = document.getElementById('hub-column');
return col ? relBox(col, layout) : null;
}
function fitDiamond() {
var wrap = document.getElementById('hub-diamond-wrap');
var diamond = document.getElementById('hub-diamond');
if (!wrap || !diamond || window.innerWidth <= 1200) return;
var rowW = wrap.clientWidth;
var rowH = wrap.clientHeight;
var fitInRow = 1.04 / Math.SQRT2;
var size = Math.min(rowW * fitInRow, rowH * fitInRow);
var scale = 0.9;
var col = document.getElementById('hub-column');
if (col) {
var v = getComputedStyle(col).getPropertyValue('--hub-diamond-scale').trim();
if (v) scale = parseFloat(v) || scale;
}
size = Math.max(Math.floor(size * scale), Math.floor(150 * scale));
diamond.style.width = size + 'px';
diamond.style.height = size + 'px';
}
function drawConnectors() {
var layout = document.querySelector('.board-layout');
var wrap = document.getElementById('hub-diamond-wrap');
var diamond = document.getElementById('hub-diamond');
var svg = document.querySelector('.connectors');
var lineGroup = document.getElementById('connector-lines');
if (!layout || !wrap || !diamond || !svg || !lineGroup) return;
fitDiamond();
if (window.innerWidth <= 1200) {
lineGroup.innerHTML = '';
svg.removeAttribute('viewBox');
return;
}
var layoutBox = layout.getBoundingClientRect();
var diamondBox = relBox(diamond, layout);
var diamondSize = diamond.offsetWidth;
var cx = diamondBox.cx;
var cy = diamondBox.cy;
svg.setAttribute('viewBox', '0 0 ' + layoutBox.width + ' ' + layoutBox.height);
lineGroup.innerHTML = '';
var topV = diamondVertex(cx, cy, diamondSize, 'top');
var bottomV = diamondVertex(cx, cy, diamondSize, 'bottom');
var msgBox = document.querySelector('.hub-postit-sheet--front');
var focusBox = document.querySelector('.hub-schedule-planner');
var hubBox = hubColumnBox(layout);
var hrmBox = document.querySelector('.dept-card--hrm');
var exBox = document.querySelector('.dept-card--ex');
var hrdBox = document.querySelector('.dept-card--hrd');
var gaBox = document.querySelector('.dept-card--ga');
var kneeXs = { left: 0, right: 0 };
if (hubBox && hrmBox && exBox) {
var innerLeft = Math.max(relBox(hrmBox, layout).right, relBox(exBox, layout).right);
kneeXs.left = (innerLeft + hubBox.left) / 2;
}
if (hubBox && hrdBox && gaBox) {
var innerRight = Math.min(relBox(hrdBox, layout).left, relBox(gaBox, layout).left);
kneeXs.right = (innerRight + hubBox.right) / 2;
}
var d = diamondSize / (2 * Math.SQRT2);
var approachGap = 32;
var leftApproachX = cx - d - approachGap;
var rightApproachX = cx + d + approachGap;
var leftRunX = Math.max(12, leftApproachX - kneeXs.left);
var rightRunX = Math.max(12, kneeXs.right - rightApproachX);
FACE_LINKS.forEach(function (link) {
var cardEl = document.querySelector(link.card);
if (!cardEl) return;
var edgeMid = diamondEdgeMidpoint(cx, cy, diamondSize, link.edge);
var runX = link.knee === 'left' ? leftRunX : rightRunX;
var approachX = link.knee === 'left' ? leftApproachX : rightApproachX;
var anchorY = anchorYForSymmetricFace(cy, edgeMid.y, runX, link.vert);
var cardAnchor = cardEdgeAnchor(cardEl, layout, link.side, anchorY);
var pathPoints = buildBentPath(cardAnchor, edgeMid, link.side, kneeXs[link.knee], approachX);
drawPolyline(lineGroup, pathPoints);
});
if (msgBox) {
var msg = relBox(msgBox, layout);
var msgAnchor = { x: cx, y: msg.bottom };
drawPolyline(lineGroup, [topV, msgAnchor]);
}
if (focusBox) {
var focus = relBox(focusBox, layout);
var focusAnchor = { x: cx, y: focus.top };
drawPolyline(lineGroup, [bottomV, focusAnchor]);
}
}
window.addEventListener('load', drawConnectors);
window.addEventListener('resize', drawConnectors);
if (document.fonts && document.fonts.ready) {
document.fonts.ready.then(function () {
requestAnimationFrame(function () {
requestAnimationFrame(drawConnectors);
});
});
}
var layoutEl = document.querySelector('.board-layout');
if (layoutEl && typeof ResizeObserver !== 'undefined') {
var resizeTimer;
new ResizeObserver(function () {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(drawConnectors, 50);
}).observe(layoutEl);
}
})();
</script>
</body>
</html>