Files
eene_dashboard/frontend/public/quarter-dashboard-preview.html
2026-06-18 15:06:37 +09:00

2056 lines
64 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!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;
/* 헤더 상태 통계(stat-*)와 동일 — 프로젝트 제목 불릿 */
--status-in-progress: #10b981;
--status-hold: #ff9f0a;
--status-done: #b0b0b0;
--status-issue: #ff5252;
/* 부서 카드 헤드 — 샴페인 골드 */
--dept-head-bg-top: #faf6ef;
--dept-head-bg-bottom: #f0e6d4;
--dept-head-text: #4a3d2e;
--dept-head-accent: #9a7b4f;
--dept-head-line: rgba(180, 152, 108, 0.32);
}
* { 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: 0;
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;
/* 중앙 허브 확대(다이아몬드 1.1×) — 좌·우 부문 카드 열은 1fr로 자동 축소 */
grid-template-columns: minmax(0, 1fr) minmax(320px, 396px) 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; }
.dept-icon {
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
width: 36px;
height: 36px;
margin-right: 8px;
border-radius: 10px;
background: rgba(255, 255, 255, 0.48);
border: 1px solid rgba(180, 152, 108, 0.24);
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, 0.62),
0 1px 2px rgba(92, 74, 50, 0.06);
color: var(--dept-head-accent);
align-self: center;
}
.dept-icon svg {
width: 32px;
height: 32px;
stroke: currentColor;
fill: none;
stroke-width: 1.75;
}
.dept-head {
position: relative;
z-index: 2;
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
margin-bottom: 0;
padding: 9px 16px 9px;
border-bottom: none;
background: linear-gradient(180deg, var(--dept-head-bg-top) 0%, var(--dept-head-bg-bottom) 100%);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.72);
flex-shrink: 0;
}
.dept-head::after {
content: "";
position: absolute;
left: 14px;
right: 14px;
bottom: 0;
height: 1px;
background: linear-gradient(
90deg,
transparent 0%,
var(--dept-head-line) 18%,
var(--dept-head-line) 82%,
transparent 100%
);
}
.dept-head-main {
display: flex;
align-items: center;
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: var(--dept-head-text);
}
.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-head-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 {
position: relative;
min-height: 0;
flex: 1;
display: flex;
flex-direction: column;
gap: 0;
overflow-y: auto;
padding: 10px 14px 10px;
background: linear-gradient(180deg, #f8fbfa 0%, rgba(248, 251, 250, 0) 20px);
}
.board-project-list::before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
height: 3px;
background: linear-gradient(
180deg,
rgba(92, 74, 50, 0.04) 0%,
transparent 100%
);
pointer-events: none;
}
.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 auto;
column-gap: 12px;
align-items: center;
}
.project-sub-divider {
display: block;
width: 1px;
align-self: stretch;
margin: 6px 0;
background: linear-gradient(
180deg,
transparent 0%,
#c8d9d0 14%,
#c8d9d0 86%,
transparent 100%
);
}
.progress-col {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
flex-shrink: 0;
width: 93px;
}
.project-fields {
display: flex;
flex-direction: column;
gap: 7px;
min-width: 0;
/* 불릿(10px) + gap(10px) — 하위 필드는 제목 글자 시작선과 정렬 */
--project-title-indent: 20px;
}
.project-field {
display: grid;
grid-template-columns: 96px 1fr;
gap: 8px;
align-items: baseline;
padding-left: var(--project-title-indent);
}
.project-sub-title {
display: flex;
align-items: flex-start;
gap: 10px;
font-size: 24px;
font-weight: 600;
color: #0a2e24;
line-height: 1.35;
}
.project-sub-title::before {
content: "";
flex-shrink: 0;
width: 10px;
height: 10px;
margin-top: 9px;
border-radius: 50%;
background: var(--status-bullet, var(--status-in-progress));
}
.project-sub-title-text {
flex: 1;
min-width: 0;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
.project-sub-title--in-progress { --status-bullet: var(--status-in-progress); }
.project-sub-title--hold { --status-bullet: var(--status-hold); }
.project-sub-title--done { --status-bullet: var(--status-done); }
.project-sub-title--issue { --status-bullet: var(--status-issue); }
.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;
}
.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.473), 171px);
/* 슬로건·일정 밴드 — 다이아몬드 1.1×에 맞춰 높이 축소 (0.624→0.567, 226→205) */
--hub-slogan-band-h: min(calc(var(--hub-row-h) * 0.567), 205px);
/* 일정: 박스 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.99;
}
.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 {
font-size: 20px;
font-weight: 500;
line-height: 1.45;
font-family: inherit;
}
.hub-column .hub-routine-item {
font-size: 24px;
font-weight: 600;
line-height: 1.35;
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 {
width: 36px;
height: 36px;
border: 2px solid var(--hrm);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: var(--hrm);
font-size: 18px;
font-weight: 700;
flex-shrink: 0;
}
.hub-diamond {
flex-shrink: 0;
transform: rotate(45deg);
background: #fff;
border: 2.5px solid var(--hrm);
box-shadow: 0 4px 18px rgba(7, 65, 46, 0.1);
display: flex;
align-items: center;
justify-content: center;
}
.hub-diamond-inner {
transform: rotate(-45deg);
width: 88%;
text-align: center;
padding: 0 4px;
}
.hub-diamond-icon {
width: 38px;
height: 38px;
margin: 0 auto 6px;
border: 2px solid var(--hrm);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: var(--hrm);
font-size: 20px;
font-weight: 700;
}
.hub-diamond-title {
font-size: 18px;
font-weight: 800;
color: #1e3a5f;
margin-bottom: 6px;
line-height: 1.3;
}
.hub-diamond ul {
list-style: none;
text-align: center;
font-size: 14px;
line-height: 1.5;
color: #334155;
font-weight: 500;
overflow: visible;
padding: 0;
}
.hub-diamond li {
padding: 1px 0;
}
.hub-diamond li::before {
content: "• ";
color: var(--hrm);
font-weight: 700;
}
@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-field">
<span class="project-field-label">프로젝트명</span>
<span class="project-field-value">상반기 채용 운영</span>
</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-field">
<span class="project-field-label">프로젝트명</span>
<span class="project-field-value">평가제도 개선</span>
</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">
<span class="progress-label">진행/달성률</span>
<div class="donut" style="--pct:60; --color:#ff9f0a"><span style="color:#ff9f0a">보류</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-field">
<span class="project-field-label">프로젝트명</span>
<span class="project-field-value">신규입사자 온보딩 프로그램</span>
</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">
<span class="progress-label">진행/달성률</span>
<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-field">
<span class="project-field-label">프로젝트명</span>
<span class="project-field-value">팀장 리더십 교육</span>
</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">
<span class="progress-label">진행/달성률</span>
<div class="donut" style="--pct:100; --color:#b0b0b0"><span style="color:#b0b0b0">완료</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">
<circle cx="12" cy="12" r="10"/>
<circle cx="12" cy="12" r="6"/>
<circle cx="12" cy="12" r="2"/>
</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>
</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-field">
<span class="project-field-label">프로젝트명</span>
<span class="project-field-value">조직문화 진단</span>
</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">
<span class="progress-label">진행/달성률</span>
<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-field">
<span class="project-field-label">프로젝트명</span>
<span class="project-field-value">복리후생제도 개선</span>
</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">
<span class="progress-label">진행/달성률</span>
<div class="donut" style="--pct:50; --color:#ff9f0a"><span style="color:#ff9f0a">보류</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-field">
<span class="project-field-label">프로젝트명</span>
<span class="project-field-value">사무공간 재배치</span>
</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">
<span class="progress-label">진행/달성률</span>
<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-field">
<span class="project-field-label">프로젝트명</span>
<span class="project-field-value">안전·보안 점검 강화</span>
</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">
<span class="progress-label">진행/달성률</span>
<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>