diff --git a/php/assets/app.css b/php/assets/app.css new file mode 100644 index 0000000..ca8004f --- /dev/null +++ b/php/assets/app.css @@ -0,0 +1,420 @@ +/* ============================================================================= + * app.css — 통합 모니터링 관리자 디자인 시스템 "Slate NOC Console" + * + * 단일 진실원(single source of truth). 7개 페이지가 이 파일 하나만 링크한다. + * + * + * 설계 원칙: + * - 모든 색/여백/반경/타이포는 :root CSS 변수. 페이지에 hex 리터럴 금지. + * - 한글 시스템 폰트 우선(폐쇄망 — 웹폰트 로드 불가). 외부 리소스 0. + * - 상태는 3중 인코딩: 색 + 도형(점/좌측레일/글리프) + 텍스트 라벨. + * (색맹·흑백 인쇄에서도 정상/누수/경보/오프라인 구분됨 — WCAG 1.4.1) + * - 명도 대비 WCAG AA(본문 4.5:1). 본문/캡션 하한 .8125rem, 라벨/배지/타임스탬프는 .75rem 허용. + * - 라이트 우선 + prefers-color-scheme 다크 자동 + 인쇄는 강제 라이트(리포트/증적). + * ============================================================================= */ + +/* ── 디자인 토큰 (라이트) ─────────────────────────────────────────────────── */ +:root { + /* 표면·잉크 */ + --bg: #eef1f5; + --surface: #ffffff; + --surface-2: #f5f7fa; + --raise: #fbfcfe; + --ink: #1b2430; /* 본문 (on surface: ~13:1) */ + --ink-2: #54606f; /* 보조 텍스트 (on white: ~5.2:1 AA) */ + --ink-3: #6b7687; /* 캡션/축라벨 (on white: ~4.5:1 AA, 최소선) */ + --line: #dce1e8; + --line-2: #eaeef3; + + /* 브랜드 (절제된 스틸블루 — 저채도라 저온 시맨틱/링크와 분리) */ + --primary: #2b5bab; + --primary-600: #234f8f; + --on-primary: #ffffff; + --primary-tint: #e9eff8; + + /* 헤더(앱바) — 라이트: 브랜드 primary 배경 + 흰 잉크 */ + --header-bg: var(--primary); + --header-ink: var(--on-primary); + + /* 상태 시맨틱 — rail/dot 용(진한 색) + ink(텍스트) + bg(옅은 배경) */ + --normal: #1f8a4c; --normal-ink: #136c39; --normal-bg: #e6f4ec; + --leak: #d12b2b; --leak-ink: #b11f1f; --leak-bg: #fbe8e8; + --warn: #b26a00; --warn-ink: #935600; --warn-bg: #f8edda; + --offline:#6b7683; --offline-ink:#4b5560; --offline-bg:#ebeef2; + + /* 지표 칩 — 서로/브랜드와 뚜렷이 구분 */ + --hot-ink: var(--leak-ink); --hot-bg: var(--leak-bg); + --cold-ink: #0b5a6e; --cold-bg: #e1f1f4; /* 티일(저온) — 스틸블루와 다름 */ + --humid-ink: var(--warn-ink); --humid-bg: var(--warn-bg); + --dry-ink: #4a4fa0; --dry-bg: #ecedf8; /* 절제된 인디고(저습, 희소) */ + + /* 차트 라인 */ + --chart-temp: #c2410c; /* 온도=따뜻 */ + --chart-hum: #0e7490; /* 습도=차가움(티일) */ + --chart-grid: var(--line); + + /* 타이포 — 한글 시스템 폰트 우선(오프라인 일관 렌더). 웹폰트 미로드. */ + --font: "Malgun Gothic","Apple SD Gothic Neo",system-ui,-apple-system,"Segoe UI",Roboto,"Noto Sans KR",sans-serif; + --mono: ui-monospace,SFMono-Regular,Consolas,"D2Coding",monospace; + + /* 4/8 간격 리듬 */ + --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px; --sp-5: 20px; --sp-6: 24px; --sp-8: 32px; + /* 반경 스케일 */ + --r-sm: 4px; --r: 8px; --r-lg: 12px; --r-pill: 999px; + /* 그림자 (절제) */ + --shadow: 0 1px 3px rgba(16,24,40,.08), 0 1px 2px rgba(16,24,40,.04); + --shadow-lg: 0 6px 20px rgba(16,24,40,.12); + --ring: 0 0 0 3px rgba(43,91,171,.28); +} + +/* ── 다크 (관제 야간/개인 선호) — 같은 토큰을 명도만 조정 ──────────────────── */ +@media (prefers-color-scheme: dark) { + :root { + --bg: #10151c; + --surface: #1a2129; + --surface-2: #212a34; + --raise: #232d38; + --ink: #e6ecf3; + --ink-2: #a3adba; + --ink-3: #8a95a2; + --line: #2b3540; + --line-2: #232c36; + + --primary: #4c8dff; + --primary-600: #6ba1ff; + --on-primary: #0d1219; + --primary-tint: #182740; + + /* 헤더 — 다크: surface-2 배경 + 본문 잉크(하단 헤어라인은 header 규칙) */ + --header-bg: var(--surface-2); + --header-ink: var(--ink); + + /* 다크 필드에서 4.5:1+ 유지 위해 명도 상향 */ + --normal: #35c775; --normal-ink: #7fe0a8; --normal-bg: #12281d; + --leak: #ff5a52; --leak-ink: #ff958e; --leak-bg: #301617; + --warn: #ffb020; --warn-ink: #ffcb6b; --warn-bg: #2d2410; + --offline:#8a94a1; --offline-ink:#aab3bf; --offline-bg:#20272f; + + --cold-ink: #5fd0e6; --cold-bg: #10262c; + --dry-ink: #a7abf0; --dry-bg: #1c1e33; + --hot-ink: var(--leak-ink); --hot-bg: var(--leak-bg); + --humid-ink: var(--warn-ink); --humid-bg: var(--warn-bg); + + --chart-temp: #ff8a5c; + --chart-hum: #43c4dc; + + --shadow: 0 1px 3px rgba(0,0,0,.5); + --shadow-lg: 0 8px 24px rgba(0,0,0,.55); + --ring: 0 0 0 3px rgba(76,141,255,.4); + } + /* 다크 헤더: primary 배너가 아닌 surface-2이므로 본문과 분리할 1px 하단 헤어라인 */ + header { border-bottom: 1px solid var(--line); } +} + +/* ── 리셋·베이스 ──────────────────────────────────────────────────────────── */ +* { box-sizing: border-box; margin: 0; padding: 0; } +html { -webkit-text-size-adjust: 100%; } +body { + font-family: var(--font); + background: var(--bg); + color: var(--ink); + line-height: 1.55; + font-size: 1rem; + -webkit-font-smoothing: antialiased; +} +/* 수치는 자릿수 고정폭(표·지표 정렬) */ +.val, .metric-chip, .report-stat strong, td.num, .num, .status-clock { font-variant-numeric: tabular-nums; } +a { color: var(--primary); } +:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; border-radius: var(--r-sm); } +img { max-width: 100%; } + +/* 타입 스케일 (4단) */ +h1 { font-size: 1.375rem; font-weight: 700; line-height: 1.3; } +h2 { font-size: 1.125rem; font-weight: 700; color: var(--ink); margin: var(--sp-6) 0 var(--sp-3); } +.panel h2, .status-hero h2 { margin-top: 0; } +label, .label { font-size: .875rem; font-weight: 600; } +.caption, small { font-size: .8125rem; color: var(--ink-3); } + +/* ── 헤더(앱바) ───────────────────────────────────────────────────────────── */ +header { + background: var(--header-bg); + color: var(--header-ink); + padding: var(--sp-4) var(--sp-6); + display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4); +} +header h1 { font-size: 1.3rem; color: var(--header-ink); } +.top-actions { display: flex; gap: var(--sp-2); align-items: center; flex-wrap: wrap; } +.top-actions a { + color: var(--header-ink); font-size: .8125rem; font-weight: 600; text-decoration: none; + background: rgba(255,255,255,.14); border: 1px solid rgba(255,255,255,.22); + padding: 6px 14px; border-radius: var(--r-sm); +} +.top-actions a:hover { background: rgba(255,255,255,.24); } + +/* ── 레이아웃 ─────────────────────────────────────────────────────────────── */ +.container { max-width: 1320px; margin: var(--sp-6) auto; padding: 0 var(--sp-4); } +.ops-grid { display: grid; grid-template-columns: minmax(0,1.5fr) minmax(280px,.9fr); + gap: var(--sp-4); align-items: start; margin-bottom: var(--sp-6); } +.cards { display: flex; gap: var(--sp-4); flex-wrap: wrap; margin-bottom: var(--sp-6); } +.sensor-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px,1fr)); + gap: var(--sp-4); margin-bottom: var(--sp-6); } + +/* ── 패널·카드 ───────────────────────────────────────────────────────────── */ +.panel, .card, .chart-panel, .leak-status-card, .empty-note { + background: var(--surface); border: 1px solid var(--line); border-radius: var(--r); +} +.panel { padding: var(--sp-5); } +.chart-panel { padding: var(--sp-5); margin-bottom: var(--sp-6); } +.card { padding: var(--sp-5) var(--sp-6); flex: 1; min-width: 180px; } +.card span { color: var(--ink-2); font-size: .8125rem; } +.card .val { font-size: 2rem; font-weight: 700; margin-top: var(--sp-1); color: var(--ink); } + +/* ── 시스템 상태 배너(hero) ──────────────────────────────────────────────── */ +.status-hero { + border-radius: var(--r); padding: var(--sp-5); 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: var(--surface); + border: 1px solid var(--line); border-left: 6px solid var(--offline); +} +.status-hero h2 { font-size: 1.25rem; display: flex; align-items: center; gap: var(--sp-2); } +.status-hero h2::before { + content: ""; width: .7em; height: .7em; border-radius: 50%; background: var(--offline); flex: none; +} +.status-hero p { color: var(--ink-2); font-size: .9rem; margin-top: 2px; } +.status-hero.normal { border-left-color: var(--normal); } +.status-hero.warning { border-left-color: var(--warn); } +.status-hero.danger { border-left-color: var(--leak); background: var(--leak-bg); } +.status-hero.normal h2::before { background: var(--normal); } +.status-hero.warning h2::before { background: var(--warn); } +.status-hero.danger h2::before { background: var(--leak); } +.status-clock { text-align: right; font-size: .8125rem; color: var(--ink-3); white-space: nowrap; } + +/* ── 센서 상태 카드 (좌측레일 + 점 + 배지 = 3중) ─────────────────────────── */ +.sensor-card { + background: var(--surface); border: 1px solid var(--line); border-radius: var(--r); + border-left: 1px solid var(--line); padding: var(--sp-5); +} +.sensor-card.alert { border-left: 6px solid var(--leak); background: var(--leak-bg); } +.sensor-card.offline { border-left: 6px solid var(--offline); background: var(--offline-bg); } + +/* 배지/알약 공통 — 앞에 점 글리프(도형 중복), 텍스트 라벨 필수 */ +.badge, .pill { + display: inline-flex; align-items: center; gap: .4em; + border-radius: var(--r-pill); padding: 3px 10px; + font-size: .75rem; font-weight: 700; line-height: 1.4; + background: var(--normal-bg); color: var(--normal-ink); +} +.badge::before, .pill::before { + content: ""; width: .5em; height: .5em; border-radius: 50%; background: currentColor; flex: none; +} +.badge.ok, .pill.ok { background: var(--normal-bg); color: var(--normal-ink); } +.badge.alert,.pill.alert { background: var(--leak-bg); color: var(--leak-ink); } +.badge.offline,.pill.offline{ background: var(--offline-bg); color: var(--offline-ink); } +.pill.high_temp { background: var(--hot-bg); color: var(--hot-ink); } +.pill.low_temp { background: var(--cold-bg); color: var(--cold-ink); } +.pill.high_humidity{ background: var(--humid-bg); color: var(--humid-ink); } +.pill.low_humidity { background: var(--dry-bg); color: var(--dry-ink); } +.pill.leak, .pill.leak_alert { background: var(--leak-bg); color: var(--leak-ink); } +.pill.leak_recovery { background: var(--normal-bg); color: var(--normal-ink); } + +/* 지표 칩 */ +.metric-line { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-3); } +.metric-chip { + display: inline-flex; align-items: center; border-radius: var(--r-pill); + background: var(--surface-2); color: var(--ink-2); + padding: 4px 10px; font-size: .78rem; font-weight: 700; +} +.metric-chip.hot { background: var(--hot-bg); color: var(--hot-ink); } +.metric-chip.cold { background: var(--cold-bg); color: var(--cold-ink); } +.metric-chip.humid { background: var(--humid-bg); color: var(--humid-ink); } +.metric-chip.dry { background: var(--dry-bg); color: var(--dry-ink); } +.metric-time { color: var(--ink-3); font-size: .75rem; margin-top: var(--sp-2); } + +/* ── 운영 자가진단 ───────────────────────────────────────────────────────── */ +.diag-list { display: grid; gap: var(--sp-2); } +.diag-item { + border: 1px solid var(--line); border-radius: var(--r); padding: 9px 10px; + display: grid; grid-template-columns: auto minmax(0,1fr); gap: var(--sp-2); align-items: start; +} +.diag-dot { width: 10px; height: 10px; border-radius: 50%; margin-top: 5px; background: var(--normal); flex: none; } +.diag-item.warn .diag-dot { background: var(--warn); } +.diag-item.critical .diag-dot { background: var(--leak); } +.diag-item strong { display: block; font-size: .8125rem; } +.diag-item span { color: var(--ink-2); font-size: .78rem; line-height: 1.4; } + +/* ── 30일 운영 요약 ─────────────────────────────────────────────────────── */ +.report-grid { display: grid; grid-template-columns: repeat(4, minmax(0,1fr)); gap: var(--sp-3); } +.report-stat { border: 1px solid var(--line); border-radius: var(--r); padding: var(--sp-3); background: var(--surface); } +.report-stat span { display: block; color: var(--ink-2); font-size: .75rem; margin-bottom: 4px; } +.report-stat strong { font-size: 1.1rem; } + +/* ── 표 ───────────────────────────────────────────────────────────────────── */ +.table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; margin-bottom: var(--sp-6); border-radius: var(--r); } +table { + width: 100%; border-collapse: collapse; background: var(--surface); + border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; +} +.table-wrap table { margin-bottom: 0; } +th { + background: var(--surface-2); font-size: .8125rem; font-weight: 700; color: var(--ink-2); + padding: 10px 14px; text-align: left; border-bottom: 1px solid var(--line); white-space: nowrap; +} +td { padding: 9px 14px; border-bottom: 1px solid var(--line-2); font-size: .875rem; color: var(--ink); } +tbody tr:hover td { background: var(--surface-2); } +.alert-row td { background: var(--leak-bg); } +.alert-row:hover td { background: var(--leak-bg); } + +/* 상태 텍스트(인라인) — 색 + 앞 글리프 */ +.ok-color, .err-color, .warn-color { font-weight: 700; } +.ok-color { color: var(--normal-ink); } +.err-color { color: var(--leak-ink); } +.warn-color{ color: var(--warn-ink); } +.ok-color::before { content: "\2713\00a0"; } /* ✓ */ +.err-color::before { content: "\2715\00a0"; } /* ✕ */ +.warn-color::before{ content: "\26a0\00a0"; } /* ⚠ */ + +/* 점검 통과/실패(설치 마법사·보안 증적) — 색만 아님, 글리프+텍스트 */ +.check.ok, .check-ok { color: var(--normal-ink); font-weight: 700; } +.check.fail, .check-fail { color: var(--leak-ink); font-weight: 700; } +.check.ok::before, .check-ok::before { content: "\2713\00a0"; } +.check.fail::before, .check-fail::before { content: "\2715\00a0"; } + +/* ── 차트 ─────────────────────────────────────────────────────────────────── */ +.chart-legend { display: flex; gap: var(--sp-4); flex-wrap: wrap; margin: var(--sp-2) 0 var(--sp-3); + font-size: .8125rem; color: var(--ink-2); } +.chart-legend span { display: inline-flex; align-items: center; gap: 6px; } +.legend-swatch { width: 14px; height: 4px; border-radius: 2px; display: inline-block; } +.legend-swatch.temp { background: var(--chart-temp); } +.legend-swatch.hum { background: var(--chart-hum); } +.chart-svg-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; } +.chart-empty, .empty-note { color: var(--ink-3); padding: var(--sp-6); text-align: center; } +.empty-note { padding: var(--sp-5); } + +/* ── 누수 패널 ───────────────────────────────────────────────────────────── */ +.leak-status-card { border-left: 1px solid var(--line); padding: var(--sp-5); } +.leak-status-card.leak { border-left: 6px solid var(--leak); background: var(--leak-bg); } +.leak-status-card.offline { border-left: 6px solid var(--offline); background: var(--offline-bg); } +.leak-thumbs { display: flex; flex-wrap: wrap; gap: var(--sp-2); } +.leak-thumbs a { display: inline-block; line-height: 0; } +.leak-thumbs img { width: 64px; height: 64px; object-fit: cover; border-radius: var(--r-sm); + border: 1px solid var(--line); background: var(--surface-2); } + +/* ── 모바일 요약 타일/링크 ──────────────────────────────────────────────── */ +.mobile-quick { display: none; } +.quick-grid { display: grid; grid-template-columns: repeat(4, minmax(0,1fr)); gap: var(--sp-2); margin-bottom: var(--sp-3); } +.quick-tile { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r); + padding: 10px; text-decoration: none; color: var(--ink); min-height: 70px; } +.quick-tile span { display: block; color: var(--ink-2); font-size: .75rem; margin-bottom: 5px; } +.quick-tile strong { font-size: 1.25rem; line-height: 1; } +.quick-tile.danger { border-color: var(--leak); background: var(--leak-bg); } +.quick-tile.warn { border-color: var(--warn); background: var(--warn-bg); } +.quick-tile.ok { border-color: var(--normal); background: var(--normal-bg); } +.quick-links { display: flex; gap: var(--sp-2); overflow-x: auto; -webkit-overflow-scrolling: touch; + padding-bottom: 6px; margin-bottom: var(--sp-4); } +.quick-links a { flex: 0 0 auto; color: var(--primary-600); background: var(--primary-tint); + border: 1px solid var(--line); text-decoration: none; border-radius: var(--r-pill); + padding: 8px 12px; font-size: .8125rem; font-weight: 700; } + +/* ── 모바일 접힘(disclosure) ────────────────────────────────────────────── */ +.mobile-detail { margin-bottom: var(--sp-6); } +.mobile-detail summary { display: none; } + +.refresh { float: right; font-size: .8125rem; color: var(--ink-2); } + +/* ── 폼 / 로그인 / 카드형 페이지 ────────────────────────────────────────── */ +.login-box { + background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg); + padding: var(--sp-8) var(--sp-6); box-shadow: var(--shadow-lg); width: 100%; max-width: 400px; +} +.login-box h1 { color: var(--primary); margin-bottom: var(--sp-2); text-align: center; } +.login-box p.sub { font-size: .875rem; color: var(--ink-2); text-align: center; margin-bottom: var(--sp-6); } +.form-group { margin-bottom: var(--sp-4); } +.form-group label { display: block; color: var(--ink-2); margin-bottom: 6px; } +.form-group input, input[type=text], input[type=password], textarea { + width: 100%; padding: 10px 14px; border: 1px solid var(--line); border-radius: var(--r); + font-size: .95rem; font-family: inherit; color: var(--ink); background: var(--surface); outline: none; +} +.form-group input:focus, input:focus, textarea:focus { border-color: var(--primary); box-shadow: var(--ring); } +/* 강제 색상(고대비/Windows High Contrast)에서는 border-color·box-shadow가 무시되어 + 입력 포커스가 사라진다 → 시스템 아웃라인으로 포커스 링 복원 */ +@media (forced-colors: active) { + input:focus, textarea:focus { outline: 2px solid; outline-offset: 1px; } +} +.btn { + display: inline-block; width: 100%; padding: 12px; background: var(--primary); color: var(--on-primary); + border: none; border-radius: var(--r); font-size: 1rem; font-weight: 700; cursor: pointer; text-align: center; +} +.btn:hover { background: var(--primary-600); } +.btn:disabled { background: var(--offline); cursor: not-allowed; } +.btn.secondary { background: var(--surface); color: var(--primary); border: 1px solid var(--line); } + +/* 배너 — 성공 배너는 .banner-ok. (생 .ok 는 .badge.ok/.pill.ok/.quick-tile.ok 와 + 특이도 동률로 충돌해 정상 배지를 사각형으로 깨뜨리므로 네임스페이스한다.) */ +.error, .expired, .banner-ok { + padding: 10px 14px; border-radius: var(--r); font-size: .875rem; margin-bottom: var(--sp-4); + border: 1px solid var(--line); border-left-width: 4px; +} +.error { background: var(--leak-bg); color: var(--leak-ink); border-left-color: var(--leak); } +.expired { background: var(--warn-bg); color: var(--warn-ink); border-left-color: var(--warn); } +.banner-ok { background: var(--normal-bg); color: var(--normal-ink); border-left-color: var(--normal); } + +/* MFA 시크릿/코드 블록 등 */ +.secret, code, .mono { + font-family: var(--mono); background: var(--surface-2); border: 1px solid var(--line); + border-radius: var(--r-sm); padding: 2px 6px; word-break: break-all; color: var(--ink); +} +.secret { display: block; padding: 12px; font-size: 1.05rem; letter-spacing: .06em; } + +/* ── 반응형 ──────────────────────────────────────────────────────────────── */ +@media (max-width: 768px) { + header { flex-direction: column; align-items: flex-start; } + .top-actions { margin-top: var(--sp-3); overflow-x: auto; flex-wrap: nowrap; -webkit-overflow-scrolling: touch; } + .top-actions a { flex: 0 0 auto; } + .status-hero { grid-template-columns: 1fr; } + .status-clock { text-align: left; } + .mobile-quick { display: block; } + .ops-grid { grid-template-columns: 1fr; } + .report-grid { grid-template-columns: repeat(2, minmax(0,1fr)); } + .cards { flex-direction: column; } + .card, .sensor-card { min-width: 0; } + header h1 { font-size: 1.1rem; } + .card .val { font-size: 1.6rem; } + th, td { padding: 8px 10px; } + td { font-size: .8125rem; } + .mobile-detail { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; } + .mobile-detail summary { display: flex; justify-content: space-between; align-items: center; gap: 10px; + padding: 13px 14px; color: var(--ink); font-weight: 700; cursor: pointer; list-style: none; } + .mobile-detail summary::-webkit-details-marker { display: none; } + .mobile-detail summary span { color: var(--ink-2); font-size: .8125rem; font-weight: 600; } + .mobile-detail .table-wrap { margin-bottom: 0; border-top: 1px solid var(--line); border-radius: 0; } +} +@media (max-width: 480px) { + .container { padding: 0 var(--sp-3); } + header { padding: var(--sp-3) var(--sp-4); } + .quick-grid { grid-template-columns: repeat(2, minmax(0,1fr)); } + .sensor-grid { grid-template-columns: 1fr; } + .card { padding: var(--sp-4); } + .col-hide-xs { display: none; } + .report-grid { grid-template-columns: 1fr; } + .login-box { padding: var(--sp-6) var(--sp-5); margin: 0 var(--sp-3); } + /* 캡션/본문 하한 유지 — 이 밑으로 축소 금지 */ + th, td { font-size: .8125rem; } +} + +/* ── 인쇄 — 강제 라이트(월간 리포트·보안 증적은 종이 가독) ────────────────── */ +@media print { + :root { + --bg: #fff; --surface: #fff; --surface-2: #fff; --raise: #fff; + --ink: #000; --ink-2: #333; --ink-3: #444; --line: #999; --line-2: #ccc; + --primary: #14315e; --on-primary: #fff; --primary-tint: #fff; + --normal-bg: #fff; --leak-bg: #fff; --warn-bg: #fff; --offline-bg: #fff; + --cold-bg: #fff; --dry-bg: #fff; + --shadow: none; --shadow-lg: none; + } + body { background: #fff; color: #000; } + header, .top-actions, .refresh, .mobile-quick, .btn { display: none !important; } + .panel, .card, table, .chart-panel, .status-hero { box-shadow: none; border: 1px solid #999; + page-break-inside: avoid; break-inside: avoid; } + .badge, .pill { border: 1px solid currentColor; } /* 흑백에서도 테두리로 구분 */ + a { color: #000; text-decoration: underline; } +} diff --git a/php/blocked.php b/php/blocked.php index 6eeb451..8888352 100644 --- a/php/blocked.php +++ b/php/blocked.php @@ -7,10 +7,15 @@ $time = date('c'); ?>
관리자에게 연락하세요.
-요청 ID: =htmlspecialchars($id)?>
관리자에게 연락하세요.
+요청 ID: =htmlspecialchars($id)?>