style(dashboard): 참고 대시보드 미학으로 재테마 — 대형 숫자 KPI·플랫 카드

참고 이미지(Geckoboard형 KPI / 인디고+골드 애널리틱스) 방향으로 시각 정리.
실제 렌더(브라우저 스크린샷)로 대시보드 4탭 + 공용 login 확인.

- KPI 스트립을 '대형 숫자 + 소형 대문자 라벨' 위계로 재구성. 상태는 라벨 앞
  상태 dot(도형+색) + 값 색 + 텍스트로 3중 인코딩(상단 그라디언트 스트립 제거).
  타일 패딩·높이 확대로 여백 확보.
- 카드 상단 3px 그라디언트 스트립 제거(.card·.kpi) → 참고처럼 평평하고 조용한
  카드. .card 상태색은 값 색상 + 미묘한 테두리 틴트로 유지(월간보고·보안증적 공용).
- 토큰: 라운드(r-lg 16→18) 상향, 그림자를 소프트·확산형으로, 장식 골드 액센트
  토큰(--accent-gold) 추가. 공용 7페이지가 토큰으로 일관 이동.

알림 스트립 좌측 액센트 바와 login/status-hero 상단 액센트는 의미있는 알림·
아이덴티티 어포던스로 유지.
This commit is contained in:
cw2007 2026-07-11 12:13:15 +09:00
parent 83f7dae6e8
commit d9ed29ba3d

View file

@ -41,10 +41,13 @@
--mono: ui-monospace,SFMono-Regular,Consolas,"D2Coding",monospace; --mono: ui-monospace,SFMono-Regular,Consolas,"D2Coding",monospace;
--sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px; --sp-5: 20px; --sp-6: 24px; --sp-8: 32px; --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px; --sp-5: 20px; --sp-6: 24px; --sp-8: 32px;
--r-sm: 6px; --r: 10px; --r-lg: 16px; --r-pill: 999px; --r-sm: 8px; --r: 12px; --r-lg: 18px; --r-pill: 999px;
--shadow: 0 1px 2px rgba(0,0,0,.4); /* 소프트·확산형 그림자(참고 대시보드처럼 카드가 표면 위에 살짝 떠 보이게) */
--shadow-lg: 0 12px 32px rgba(0,0,0,.45); --shadow: 0 2px 10px rgba(0,0,0,.30);
--shadow-lg: 0 16px 40px rgba(0,0,0,.48);
--ring: 0 0 0 3px rgba(108,123,255,.45); --ring: 0 0 0 3px rgba(108,123,255,.45);
/* 장식 골드 액센트(참고 2.png 인디고+골드) — 상태색 --warn 과 별개의 장식 역할 */
--accent-gold: #ffc24b;
} }
* { box-sizing: border-box; margin: 0; padding: 0; } * { box-sizing: border-box; margin: 0; padding: 0; }
@ -93,8 +96,7 @@ header h1::before { content: ""; width: 10px; height: 10px; border-radius: 50%;
.panel { padding: var(--sp-5); } .panel { padding: var(--sp-5); }
.chart-panel { padding: var(--sp-5); margin-bottom: var(--sp-6); } .chart-panel { padding: var(--sp-5); margin-bottom: var(--sp-6); }
.card { padding: var(--sp-5) var(--sp-5) var(--sp-6); position: relative; overflow: hidden; } .card { padding: var(--sp-5) var(--sp-5) var(--sp-6); position: relative; }
.card::before { content: ""; position: absolute; inset: 0 0 auto 0; height: 3px; background: linear-gradient(90deg, var(--primary), var(--chart-hum)); opacity: .9; }
.card > div:first-child { color: var(--ink-2); font-size: .78rem; font-weight: 600; letter-spacing: .04em; text-transform: uppercase; } .card > div:first-child { color: var(--ink-2); font-size: .78rem; font-weight: 600; letter-spacing: .04em; text-transform: uppercase; }
.card span { color: var(--ink-2); font-size: .8125rem; } .card span { color: var(--ink-2); font-size: .8125rem; }
.card .val { font-size: clamp(2.4rem, 4.2vw, 3.4rem); font-weight: 800; line-height: 1.02; margin-top: var(--sp-2); color: var(--ink); letter-spacing: -.02em; } .card .val { font-size: clamp(2.4rem, 4.2vw, 3.4rem); font-weight: 800; line-height: 1.02; margin-top: var(--sp-2); color: var(--ink); letter-spacing: -.02em; }
@ -103,9 +105,10 @@ header h1::before { content: ""; width: 10px; height: 10px; border-radius: 50%;
.card .val.ok-color { color: var(--normal-ink); } .card .val.ok-color { color: var(--normal-ink); }
.card .val.err-color { color: var(--leak-ink); } .card .val.err-color { color: var(--leak-ink); }
.card .val.warn-color { color: var(--warn-ink); } .card .val.warn-color { color: var(--warn-ink); }
.card:has(.val.ok-color)::before { background: var(--normal); } /* 상태색은 .val 색상으로 인코딩(상단 스트립 제거 — 참고 대시보드 스타일의 평평한 카드) */
.card:has(.val.err-color)::before { background: var(--leak); } .card.ok, .card:has(.val.ok-color) { border-color: rgba(53,214,160,.32); }
.card:has(.val.warn-color)::before { background: var(--warn); } .card.err, .card:has(.val.err-color) { border-color: rgba(255,84,112,.34); }
.card.warn, .card:has(.val.warn-color) { border-color: rgba(255,178,62,.32); }
.card .val.ok-color::before, .card .val.err-color::before, .card .val.warn-color::before { content: none; } .card .val.ok-color::before, .card .val.err-color::before, .card .val.warn-color::before { content: none; }
.status-hero { border-radius: var(--r-lg); padding: var(--sp-6); margin-bottom: var(--sp-5); display: grid; grid-template-columns: minmax(0,1fr) auto; gap: var(--sp-4); align-items: center; color: var(--ink); background: linear-gradient(180deg, rgba(53,214,160,.08), transparent 70%), var(--surface); border: 1px solid var(--line); position: relative; overflow: hidden; } .status-hero { border-radius: var(--r-lg); padding: var(--sp-6); margin-bottom: var(--sp-5); display: grid; grid-template-columns: minmax(0,1fr) auto; gap: var(--sp-4); align-items: center; color: var(--ink); background: linear-gradient(180deg, rgba(53,214,160,.08), transparent 70%), var(--surface); border: 1px solid var(--line); position: relative; overflow: hidden; }
@ -536,20 +539,20 @@ tbody tr:hover td { background: var(--surface-2); }
margin-bottom: var(--sp-2); margin-bottom: var(--sp-2);
} }
.kpi { .kpi {
display: flex; flex-direction: column; justify-content: center; gap: 2px; display: flex; flex-direction: column; justify-content: center; gap: 6px;
background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg);
box-shadow: var(--shadow); padding: var(--sp-3) var(--sp-4); min-height: 76px; box-shadow: var(--shadow); padding: var(--sp-4) var(--sp-5); min-height: 104px;
text-decoration: none; color: var(--ink); position: relative; overflow: hidden; text-decoration: none; color: var(--ink); transition: border-color .12s ease, transform .12s ease;
} }
.kpi::before { content: ""; position: absolute; inset: 0 0 auto 0; height: 3px; background: var(--primary); } .kpi:hover { border-color: var(--primary); transform: translateY(-2px); }
.kpi:hover { border-color: var(--primary); } /* 상태 3중 인코딩: 라벨 앞 상태 dot(도형+색) + 값 색 + 텍스트 — 상단 스트립 없이 */
.kpi .kpi-lbl { color: var(--ink-2); font-size: .72rem; font-weight: 600; letter-spacing: .03em; text-transform: uppercase; } .kpi .kpi-lbl { display: flex; align-items: center; gap: 7px; color: var(--ink-2); font-size: .72rem; font-weight: 600; letter-spacing: .04em; text-transform: uppercase; }
.kpi .kpi-val { font-size: clamp(1.3rem, 2.2vw, 1.7rem); font-weight: 800; line-height: 1.1; letter-spacing: -.02em; font-variant-numeric: tabular-nums; } .kpi .kpi-lbl::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--normal); flex: none; }
.kpi .kpi-val { font-size: clamp(1.6rem, 2.8vw, 2.15rem); font-weight: 800; line-height: 1.05; letter-spacing: -.025em; font-variant-numeric: tabular-nums; }
.kpi .kpi-sub { color: var(--ink-3); font-size: .72rem; font-variant-numeric: tabular-nums; } .kpi .kpi-sub { color: var(--ink-3); font-size: .72rem; font-variant-numeric: tabular-nums; }
.kpi.ok::before { background: var(--normal); } .kpi.warn .kpi-lbl::before { background: var(--warn); }
.kpi.warn::before { background: var(--warn); } .kpi.err .kpi-lbl::before { background: var(--leak); }
.kpi.err::before { background: var(--leak); } .kpi.ok .kpi-val { color: var(--ink); }
.kpi.ok .kpi-val { color: var(--normal-ink); }
.kpi.warn .kpi-val { color: var(--warn-ink); } .kpi.warn .kpi-val { color: var(--warn-ink); }
.kpi.err .kpi-val { color: var(--leak-ink); } .kpi.err .kpi-val { color: var(--leak-ink); }