32fc12e283
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
604 lines
14 KiB
CSS
604 lines
14 KiB
CSS
/* ════════════════════════════════════════════════════
|
|
ERP 대시보드 — DESIGN.md 기반 (Monochromatic / shadcn)
|
|
════════════════════════════════════════════════════ */
|
|
|
|
/* Geist 폰트 — CDN. 실패시 Inter / 시스템 폰트 fallback */
|
|
@import url("https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600&family=Geist+Mono&family=Inter:wght@400;500;600&display=swap");
|
|
|
|
:root {
|
|
/* Colors */
|
|
--color-canvas-white: #ffffff;
|
|
--color-ghost-gray: #f2f2f2;
|
|
--color-subtle-ash: #e5e5e5;
|
|
--color-midtone-gray: #737373;
|
|
--color-rich-black: #0a0a0a;
|
|
--color-deep-black: #000000;
|
|
--color-callout-red: #c22b10;
|
|
--color-success-green:#10c22b;
|
|
|
|
/* Typography */
|
|
--font-geist: 'Geist', 'Inter', ui-sans-serif, system-ui, -apple-system,
|
|
BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
--font-geist-mono: 'Geist Mono', ui-monospace, SFMono-Regular, Menlo,
|
|
Monaco, Consolas, monospace;
|
|
|
|
--text-caption: 12px;
|
|
--text-body: 14px;
|
|
--text-heading: 18px;
|
|
--text-display: 48px;
|
|
--leading-body: 1.43;
|
|
|
|
--tracking-heading: -0.45px;
|
|
--tracking-display: -2.4px;
|
|
|
|
/* Spacing */
|
|
--sp-4: 4px; --sp-6: 6px; --sp-8: 8px; --sp-10: 10px;
|
|
--sp-12: 12px; --sp-16: 16px; --sp-20: 20px; --sp-24: 24px;
|
|
--sp-32: 32px; --sp-40: 40px; --sp-80: 80px;
|
|
|
|
/* Radii */
|
|
--r-pill: 9999px;
|
|
--r-badge: 26px;
|
|
--r-card: 14px;
|
|
--r-input: 10px;
|
|
--r-btn: 10px;
|
|
|
|
/* Shadows */
|
|
--shadow-card: oklab(0.145 -0.00000143796 0.00000340492 / 0.1) 0px 0px 0px 1px;
|
|
--shadow-focus: lab(100 0 0) 0px 0px 0px 2px;
|
|
}
|
|
|
|
/* ── 리셋 ── (auth pages 와 충돌 방지 위해 erp-shell 안에서만 적용) */
|
|
.erp-shell, .erp-shell * { box-sizing: border-box; }
|
|
.erp-shell { margin: 0; padding: 0; }
|
|
|
|
body.erp-body {
|
|
margin: 0;
|
|
font-family: var(--font-geist);
|
|
font-size: var(--text-body);
|
|
line-height: var(--leading-body);
|
|
color: var(--color-rich-black);
|
|
background: var(--color-canvas-white);
|
|
-webkit-font-smoothing: antialiased;
|
|
letter-spacing: 0;
|
|
}
|
|
|
|
.erp-body a { color: inherit; text-decoration: none; }
|
|
|
|
/* ── 상단 네비게이션 ── */
|
|
.erp-nav {
|
|
position: sticky;
|
|
top: 0;
|
|
z-index: 50;
|
|
background: var(--color-canvas-white);
|
|
border-bottom: 1px solid var(--color-subtle-ash);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 0 var(--sp-24);
|
|
height: 56px;
|
|
}
|
|
|
|
.erp-nav-left {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--sp-16);
|
|
}
|
|
|
|
.erp-brand {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--sp-8);
|
|
font-weight: 600;
|
|
color: var(--color-deep-black);
|
|
font-size: var(--text-body);
|
|
letter-spacing: -0.2px;
|
|
}
|
|
|
|
.erp-brand-logo {
|
|
height: 36px;
|
|
width: auto;
|
|
object-fit: contain;
|
|
}
|
|
|
|
.erp-brand-divider {
|
|
width: 1px;
|
|
height: 20px;
|
|
background: var(--color-subtle-ash);
|
|
}
|
|
|
|
.erp-brand-system {
|
|
font-size: var(--text-body);
|
|
font-weight: 500;
|
|
color: var(--color-rich-black);
|
|
}
|
|
|
|
.erp-nav-right {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--sp-8);
|
|
}
|
|
|
|
.erp-user-chip {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: var(--sp-8);
|
|
padding: 4px var(--sp-12) 4px 4px;
|
|
border: 1px solid var(--color-subtle-ash);
|
|
border-radius: var(--r-pill);
|
|
background: var(--color-canvas-white);
|
|
font-size: var(--text-caption);
|
|
color: var(--color-rich-black);
|
|
line-height: 1;
|
|
}
|
|
|
|
.erp-user-avatar {
|
|
width: 28px;
|
|
height: 28px;
|
|
border-radius: 50%;
|
|
object-fit: cover;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.erp-user-avatar-fallback {
|
|
width: 28px;
|
|
height: 28px;
|
|
border-radius: 50%;
|
|
background: var(--color-deep-black);
|
|
color: var(--color-canvas-white);
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: var(--text-caption);
|
|
font-weight: 600;
|
|
}
|
|
|
|
.erp-user-info {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 2px;
|
|
}
|
|
|
|
.erp-user-name {
|
|
font-weight: 500;
|
|
color: var(--color-rich-black);
|
|
font-size: var(--text-caption);
|
|
}
|
|
|
|
.erp-user-email {
|
|
color: var(--color-midtone-gray);
|
|
font-size: 11px;
|
|
}
|
|
|
|
/* ── 버튼 ── */
|
|
.erp-btn {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: var(--sp-6);
|
|
font-family: inherit;
|
|
font-size: var(--text-caption);
|
|
font-weight: 500;
|
|
line-height: 1;
|
|
border: 1px solid transparent;
|
|
border-radius: var(--r-btn);
|
|
cursor: pointer;
|
|
white-space: nowrap;
|
|
transition: background 120ms, border-color 120ms, color 120ms;
|
|
}
|
|
|
|
.erp-btn-primary {
|
|
background: var(--color-deep-black);
|
|
color: var(--color-canvas-white);
|
|
padding: 8px 16px;
|
|
}
|
|
|
|
.erp-btn-primary:hover {
|
|
background: var(--color-rich-black);
|
|
}
|
|
|
|
/* 검정 배경 요소는 글자 무조건 흰색.
|
|
<a> 버튼/배지의 a:link/a:visited(특이도 0,1,1)가 클래스 색을 덮어쓰는 문제 차단. */
|
|
a.erp-btn-primary, a.erp-btn-primary:link, a.erp-btn-primary:visited, a.erp-btn-primary:hover,
|
|
.erp-badge-inverse, a.erp-badge-inverse:link, a.erp-badge-inverse:visited,
|
|
.erp-sidebar-item.is-active, a.erp-sidebar-item.is-active:link, a.erp-sidebar-item.is-active:visited {
|
|
color: var(--color-canvas-white) !important;
|
|
}
|
|
|
|
.erp-btn-ghost {
|
|
background: transparent;
|
|
color: var(--color-rich-black);
|
|
padding: 6px 12px;
|
|
border-radius: var(--r-pill);
|
|
}
|
|
|
|
.erp-btn-ghost:hover {
|
|
background: var(--color-ghost-gray);
|
|
}
|
|
|
|
.erp-btn-outline {
|
|
background: var(--color-canvas-white);
|
|
color: var(--color-rich-black);
|
|
border-color: var(--color-subtle-ash);
|
|
padding: 6px 12px;
|
|
}
|
|
|
|
.erp-btn-outline:hover {
|
|
background: var(--color-ghost-gray);
|
|
}
|
|
|
|
.erp-btn-danger {
|
|
background: transparent;
|
|
color: var(--color-callout-red);
|
|
border-color: var(--color-subtle-ash);
|
|
padding: 6px 12px;
|
|
}
|
|
|
|
.erp-btn-danger:hover {
|
|
border-color: var(--color-callout-red);
|
|
background: rgba(194, 43, 16, 0.04);
|
|
}
|
|
|
|
/* ── 본문 컨테이너 ── */
|
|
.erp-main {
|
|
max-width: 1200px;
|
|
margin: 0 auto;
|
|
padding: var(--sp-40) var(--sp-24);
|
|
}
|
|
|
|
.erp-greeting {
|
|
margin: 0 0 var(--sp-8);
|
|
font-size: 28px;
|
|
font-weight: 600;
|
|
color: var(--color-deep-black);
|
|
letter-spacing: -0.6px;
|
|
line-height: 1.2;
|
|
}
|
|
|
|
.erp-greeting-sub {
|
|
margin: 0 0 var(--sp-32);
|
|
color: var(--color-midtone-gray);
|
|
font-size: var(--text-body);
|
|
}
|
|
|
|
.erp-section-head {
|
|
display: flex;
|
|
align-items: baseline;
|
|
justify-content: space-between;
|
|
margin-bottom: var(--sp-16);
|
|
}
|
|
|
|
.erp-section-title {
|
|
font-size: var(--text-heading);
|
|
font-weight: 500;
|
|
color: var(--color-deep-black);
|
|
letter-spacing: var(--tracking-heading);
|
|
line-height: 1.33;
|
|
}
|
|
|
|
.erp-section-meta {
|
|
font-size: var(--text-caption);
|
|
color: var(--color-midtone-gray);
|
|
}
|
|
|
|
/* ── 카드 그리드 ── */
|
|
.erp-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
|
gap: var(--sp-16);
|
|
}
|
|
|
|
.erp-card {
|
|
position: relative;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--sp-12);
|
|
background: var(--color-canvas-white);
|
|
border-radius: var(--r-card);
|
|
box-shadow: var(--shadow-card);
|
|
padding: var(--sp-20);
|
|
min-height: 180px;
|
|
transition: box-shadow 120ms, transform 120ms;
|
|
}
|
|
|
|
.erp-card[data-clickable="true"]:hover {
|
|
box-shadow: oklab(0.145 -0.00000143796 0.00000340492 / 0.18) 0 0 0 1px,
|
|
oklab(0.145 -0.00000143796 0.00000340492 / 0.06) 0 8px 24px;
|
|
}
|
|
|
|
.erp-card[data-clickable="false"] {
|
|
background: var(--color-ghost-gray);
|
|
}
|
|
|
|
.erp-card-head {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: var(--sp-8);
|
|
}
|
|
|
|
.erp-card-title {
|
|
font-size: var(--text-heading);
|
|
font-weight: 600;
|
|
color: var(--color-deep-black);
|
|
letter-spacing: var(--tracking-heading);
|
|
line-height: 1.2;
|
|
}
|
|
|
|
.erp-card-subtitle {
|
|
font-family: var(--font-geist-mono);
|
|
font-size: var(--text-caption);
|
|
color: var(--color-midtone-gray);
|
|
letter-spacing: 0;
|
|
}
|
|
|
|
.erp-card-desc {
|
|
font-size: var(--text-body);
|
|
color: var(--color-midtone-gray);
|
|
flex: 1;
|
|
}
|
|
|
|
.erp-card-foot {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: var(--sp-8);
|
|
margin-top: auto;
|
|
padding-top: var(--sp-12);
|
|
border-top: 1px solid var(--color-subtle-ash);
|
|
}
|
|
|
|
.erp-card-link {
|
|
font-size: var(--text-caption);
|
|
font-weight: 500;
|
|
color: var(--color-deep-black);
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: var(--sp-4);
|
|
}
|
|
|
|
.erp-card-link svg {
|
|
transition: transform 120ms;
|
|
}
|
|
|
|
.erp-card[data-clickable="true"]:hover .erp-card-link svg {
|
|
transform: translateX(2px);
|
|
}
|
|
|
|
/* ── 배지 ── */
|
|
.erp-badge {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: var(--sp-6);
|
|
padding: 2px 8px;
|
|
font-size: 11px;
|
|
font-weight: 500;
|
|
border-radius: var(--r-badge);
|
|
line-height: 1.4;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.erp-badge-inverse {
|
|
background: var(--color-deep-black);
|
|
color: var(--color-canvas-white);
|
|
}
|
|
|
|
.erp-badge-neutral {
|
|
background: var(--color-ghost-gray);
|
|
color: var(--color-rich-black);
|
|
}
|
|
|
|
.erp-badge-outline {
|
|
background: transparent;
|
|
color: var(--color-rich-black);
|
|
border: 1px solid #a1a1a1;
|
|
}
|
|
|
|
.erp-badge-success { background: #e6f8e9; color: var(--color-success-green); border: 1px solid #c2efc8; }
|
|
.erp-badge-danger { background: #fbe9e6; color: var(--color-callout-red); border: 1px solid #efc6bf; }
|
|
|
|
.erp-badge-dot::before {
|
|
content: "";
|
|
width: 6px;
|
|
height: 6px;
|
|
border-radius: 50%;
|
|
background: currentColor;
|
|
}
|
|
|
|
/* ── 잠긴 카드 표시 ── */
|
|
.erp-locked-overlay {
|
|
position: absolute;
|
|
top: var(--sp-12);
|
|
right: var(--sp-12);
|
|
font-size: 11px;
|
|
color: var(--color-midtone-gray);
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 4px;
|
|
}
|
|
|
|
/* ── 관리자 페이지 ── */
|
|
.erp-admin-toolbar {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: var(--sp-12);
|
|
margin-bottom: var(--sp-16);
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.erp-input {
|
|
font-family: inherit;
|
|
font-size: var(--text-body);
|
|
color: var(--color-rich-black);
|
|
background: var(--color-canvas-white);
|
|
border: 1px solid var(--color-subtle-ash);
|
|
border-radius: var(--r-input);
|
|
padding: 6px var(--sp-10);
|
|
min-width: 240px;
|
|
}
|
|
|
|
.erp-input:focus {
|
|
outline: none;
|
|
box-shadow: var(--shadow-focus);
|
|
border-color: var(--color-deep-black);
|
|
}
|
|
|
|
.erp-table-wrap {
|
|
border-radius: var(--r-card);
|
|
box-shadow: var(--shadow-card);
|
|
background: var(--color-canvas-white);
|
|
overflow: hidden;
|
|
}
|
|
|
|
.erp-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
font-size: var(--text-body);
|
|
}
|
|
|
|
.erp-table thead th {
|
|
text-align: left;
|
|
font-size: var(--text-caption);
|
|
font-weight: 500;
|
|
color: var(--color-midtone-gray);
|
|
background: var(--color-ghost-gray);
|
|
padding: var(--sp-10) var(--sp-12);
|
|
border-bottom: 1px solid var(--color-subtle-ash);
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.erp-table tbody td {
|
|
padding: var(--sp-12);
|
|
border-bottom: 1px solid var(--color-subtle-ash);
|
|
vertical-align: middle;
|
|
}
|
|
|
|
.erp-table tbody tr:last-child td {
|
|
border-bottom: none;
|
|
}
|
|
|
|
.erp-table tbody tr[data-dirty="true"] {
|
|
background: #fffbeb;
|
|
}
|
|
|
|
.erp-user-cell {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--sp-10);
|
|
}
|
|
|
|
.erp-user-cell .erp-user-avatar,
|
|
.erp-user-cell .erp-user-avatar-fallback {
|
|
width: 32px;
|
|
height: 32px;
|
|
font-size: 13px;
|
|
}
|
|
|
|
.erp-user-cell-name {
|
|
font-weight: 500;
|
|
color: var(--color-rich-black);
|
|
line-height: 1.2;
|
|
}
|
|
|
|
.erp-user-cell-email {
|
|
font-size: 12px;
|
|
color: var(--color-midtone-gray);
|
|
line-height: 1.2;
|
|
margin-top: 2px;
|
|
}
|
|
|
|
/* shadcn-style 토글 (checkbox 기반) */
|
|
.erp-switch {
|
|
position: relative;
|
|
display: inline-block;
|
|
width: 36px;
|
|
height: 20px;
|
|
}
|
|
.erp-switch input { opacity: 0; width: 0; height: 0; }
|
|
.erp-switch-slider {
|
|
position: absolute;
|
|
inset: 0;
|
|
background: var(--color-subtle-ash);
|
|
border-radius: var(--r-pill);
|
|
cursor: pointer;
|
|
transition: background 120ms;
|
|
}
|
|
.erp-switch-slider::before {
|
|
content: "";
|
|
position: absolute;
|
|
width: 16px; height: 16px;
|
|
left: 2px; top: 2px;
|
|
background: var(--color-canvas-white);
|
|
border-radius: 50%;
|
|
transition: transform 120ms;
|
|
box-shadow: 0 1px 2px rgba(0,0,0,.2);
|
|
}
|
|
.erp-switch input:checked + .erp-switch-slider { background: var(--color-deep-black); }
|
|
.erp-switch input:checked + .erp-switch-slider::before { transform: translateX(16px); }
|
|
.erp-switch input:disabled + .erp-switch-slider {
|
|
opacity: 0.5;
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
/* shadcn-style select */
|
|
.erp-select {
|
|
font-family: inherit;
|
|
font-size: var(--text-body);
|
|
color: var(--color-rich-black);
|
|
background: var(--color-canvas-white);
|
|
border: 1px solid var(--color-subtle-ash);
|
|
border-radius: var(--r-input);
|
|
padding: 4px var(--sp-10);
|
|
cursor: pointer;
|
|
}
|
|
|
|
.erp-select:focus {
|
|
outline: none;
|
|
box-shadow: var(--shadow-focus);
|
|
border-color: var(--color-deep-black);
|
|
}
|
|
|
|
.erp-select:disabled {
|
|
background: var(--color-ghost-gray);
|
|
cursor: not-allowed;
|
|
color: var(--color-midtone-gray);
|
|
}
|
|
|
|
/* 토스트 */
|
|
.erp-toast {
|
|
position: fixed;
|
|
bottom: 24px;
|
|
right: 24px;
|
|
background: var(--color-deep-black);
|
|
color: var(--color-canvas-white);
|
|
padding: var(--sp-12) var(--sp-16);
|
|
border-radius: var(--r-input);
|
|
font-size: var(--text-body);
|
|
z-index: 1000;
|
|
opacity: 0;
|
|
transform: translateY(8px);
|
|
transition: opacity 200ms, transform 200ms;
|
|
pointer-events: none;
|
|
max-width: 360px;
|
|
}
|
|
.erp-toast[data-visible="true"] {
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
}
|
|
.erp-toast[data-type="error"] {
|
|
background: var(--color-callout-red);
|
|
}
|
|
|
|
/* 반응형 */
|
|
@media (max-width: 640px) {
|
|
.erp-nav { padding: 0 var(--sp-16); height: 52px; }
|
|
.erp-brand-system { display: none; }
|
|
.erp-user-info { display: none; }
|
|
.erp-main { padding: var(--sp-24) var(--sp-16); }
|
|
.erp-greeting { font-size: 22px; }
|
|
.erp-table thead { display: none; }
|
|
.erp-table tbody td { display: block; border: none; padding: 4px var(--sp-12); }
|
|
.erp-table tbody tr { display: block; padding: var(--sp-12) 0; border-bottom: 1px solid var(--color-subtle-ash); }
|
|
}
|