POSA_Copyrighter/web/operator-gui/styles.css
changukyu 177e365b55 fix: 페르소나 리뷰 권고 1~3 — 판정 시점 내보내기, '위험'은 검토 순서, 운영 모드 문서
① 내부 내보내기가 현재 점수·현재 사용 표시 대신 decisionSnapshot 을 읽는다. 드리프트는
   currentRiskScore·scoredVersion 열로 드러낸다. 스냅샷 없는 옛 행은 no-snapshot.
② 큐 열 '위험' → '검토 우선'(침해 판정 아님), 점수 구성 패널에 범위 한 줄, 가이드 명시.
③ docs/operations/operating-modes.md: 전체 egress / API 호스트만 / 완전 폐쇄에서 점수가
   뜻하는 것. 완전 폐쇄는 키를 빼야 한다(남겨 두면 큐 전체가 실패 하한 30).

verify.ps1: ruff clean, 681 passed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BStHFrjQj2VypecSG9ex1V
2026-09-25 18:24:26 +09:00

3347 lines
66 KiB
CSS

/* =====================================================================
권리 검수 콘솔 — clean review instrument
Flat, neutral, single-accent restyle for long review sessions.
Air-gapped safe: Pretendard Variable is bundled locally (no CDN).
CSS-only: every app.js class hook and grid template is preserved.
===================================================================== */
@font-face {
font-family: "Pretendard Variable";
src: url("assets/fonts/PretendardVariable.woff2") format("woff2-variations");
font-weight: 45 920;
font-style: normal;
font-display: swap;
}
:root {
/* --- Type ---------------------------------------------------------- */
--font-ui: "Pretendard Variable", Pretendard, "Malgun Gothic", "Apple SD Gothic Neo", "Segoe UI", system-ui, sans-serif;
--font-mono: "Cascadia Mono", "Consolas", ui-monospace, "DejaVu Sans Mono", monospace;
/* --- Surfaces (neutral cool) --------------------------------------- */
--paper: #f3f5f7;
--paper-2: #e9edf0;
--card: #fcfdfe;
--card-raised: #ffffff;
--card-sunk: #f4f6f8;
--ink: #1a2128;
--ink-soft: #51606b;
--ink-faint: #8794a1;
/* --- Hairlines ----------------------------------------------------- */
--hair: #dde3e8;
--hair-soft: #e7ecf0;
--hair-strong: #b9c4cd;
/* --- Brand / accents ----------------------------------------------- */
--teal: #1f6f8b;
--teal-deep: #14495c;
--teal-tint: #e7f1f5;
--teal-tint-soft: #eef6f9;
--teal-line: #a9cdda;
--ochre: #b07d18;
--ochre-tint: #faf2dd;
--ochre-tint-soft: #fdf9ee;
--ochre-line: #e2c887;
/* --- Dark rail ----------------------------------------------------- */
--rail: #222b33;
--rail-edge: #10171d;
--rail-ink: #d3dce4;
--rail-ink-soft: #9fb0bd;
--rail-ink-strong: #e8edf2;
/* --- Risk / signal semantics --------------------------------------- */
--red: #b03a2e; --red-tint: #fceae7; --red-line: #e4aca3;
--amber: #93620c; --amber-tint: #faf1d8; --amber-line: #e0c581;
--green: #25684a; --green-tint: #e7f3ec; --green-line: #a6d3b9;
--violet: #564d75; --violet-tint: #efebf6;--violet-line: #c7bbd9;
--blue: #2c5a8c; --blue-tint: #e8f0fa; --blue-line: #b1c6e2;
--forest: #215633; --forest-tint: #ecf7ef;--forest-line: #b1d5b9;
--slate: #4c5d6b; --slate-tint: #eef2f5; --slate-line: #c2cdd6;
/* --- Geometry & elevation ------------------------------------------ */
--r-sm: 6px;
--radius: 9px;
--r-lg: 14px;
--r-pill: 999px;
--shadow-sm: 0 1px 2px rgba(23, 32, 41, 0.06);
--shadow: 0 1px 3px rgba(23, 32, 41, 0.05), 0 10px 24px -18px rgba(23, 32, 41, 0.25);
--shadow-lg: 0 18px 48px -20px rgba(16, 28, 38, 0.35), 0 3px 8px rgba(23, 32, 41, 0.05);
--press: inset 0 1px 0 rgba(255, 255, 255, 0.55);
--inset-well: inset 0 1px 2px rgba(23, 32, 41, 0.04);
--bevel: var(--bevel);
--ease: cubic-bezier(0.22, 0.61, 0.36, 1);
--audit-object-width: 24%;
}
* {
box-sizing: border-box;
}
html {
min-height: 100%;
background: var(--paper);
color: var(--ink);
font-family: var(--font-ui);
letter-spacing: 0;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
}
body {
min-height: 100vh;
margin: 0;
color: var(--ink);
background-color: var(--paper);
font-variant-numeric: tabular-nums;
}
::selection {
background: color-mix(in srgb, var(--teal) 22%, transparent);
color: var(--ink);
}
button,
input,
select,
textarea {
font: inherit;
letter-spacing: 0;
}
button {
cursor: pointer;
}
button:disabled,
input:disabled,
select:disabled,
textarea:disabled {
cursor: not-allowed;
opacity: 0.55;
}
:focus-visible {
outline: 2px solid var(--teal);
outline-offset: 2px;
border-radius: 4px;
}
/* Themed thin scrollbars — air-gap safe */
* {
scrollbar-width: thin;
scrollbar-color: var(--hair-strong) transparent;
}
*::-webkit-scrollbar {
width: 11px;
height: 11px;
}
*::-webkit-scrollbar-thumb {
border: 3px solid transparent;
border-radius: 999px;
background-clip: padding-box;
background-color: var(--hair-strong);
}
*::-webkit-scrollbar-thumb:hover {
background-color: var(--ink-faint);
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
.app-shell {
position: relative;
z-index: 1;
display: grid;
grid-template-columns: 248px minmax(0, 1fr);
min-height: 100vh;
}
/* ====================== Navigation rail ============================== */
.nav-rail {
position: sticky;
top: 0;
display: flex;
flex-direction: column;
gap: 6px;
height: 100vh;
padding: 20px 14px 16px;
background: var(--rail);
color: var(--rail-ink-strong);
border-right: 1px solid var(--rail-edge);
box-shadow: inset -1px 0 0 rgba(255, 255, 255, 0.04);
}
.brand-block {
display: flex;
align-items: center;
gap: 12px;
min-height: 58px;
margin-bottom: 14px;
padding: 0 6px 14px;
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}
.brand-block strong,
.brand-block span {
display: block;
}
.brand-block strong {
font-size: 17px;
line-height: 1.2;
letter-spacing: -0.01em;
}
.brand-block div span {
margin-top: 4px;
color: var(--rail-ink-soft);
font-size: 11px;
letter-spacing: 0.12em;
text-transform: uppercase;
}
.brand-mark {
display: inline-grid;
place-items: center;
width: 44px;
height: 44px;
border-radius: 10px;
background: var(--teal);
color: #fff;
font-weight: 750;
font-size: 17px;
letter-spacing: 0.04em;
box-shadow: var(--bevel);
}
.nav-button {
position: relative;
display: grid;
grid-template-columns: 28px minmax(0, 1fr);
align-items: center;
gap: 11px;
width: 100%;
min-height: 44px;
padding: 9px 11px;
border: 1px solid transparent;
border-radius: var(--radius);
background: transparent;
color: var(--rail-ink);
text-align: left;
font-size: 14px;
transition: background 160ms var(--ease), color 160ms var(--ease), transform 120ms var(--ease);
}
.nav-button:hover {
background: rgba(255, 255, 255, 0.07);
color: #fff;
}
.nav-button.active {
background: var(--card-raised);
color: var(--ink);
box-shadow: var(--shadow-sm);
}
.nav-button.active::before {
content: "";
position: absolute;
left: -14px;
top: 50%;
width: 4px;
height: 24px;
transform: translateY(-50%);
border-radius: 0 4px 4px 0;
background: var(--teal);
}
.nav-button span:first-child {
display: inline-grid;
place-items: center;
width: 28px;
height: 28px;
border: 1px solid currentColor;
border-radius: 7px;
font-size: 12px;
font-weight: 700;
opacity: 0.85;
}
.nav-button.active span:first-child {
border-color: var(--teal);
background: var(--teal);
color: #fff;
opacity: 1;
}
.nav-button span:last-child {
min-width: 0;
overflow-wrap: anywhere;
}
.nav-footer {
display: flex;
align-items: center;
gap: 8px;
margin-top: auto;
padding: 11px 12px;
border: 1px solid rgba(255, 255, 255, 0.14);
border-radius: var(--radius);
color: var(--rail-ink);
font-size: 12px;
letter-spacing: 0.06em;
text-transform: uppercase;
}
.status-dot {
position: relative;
width: 9px;
height: 9px;
border-radius: 50%;
background: var(--hair-strong);
}
.status-dot.ok {
background: #6fc188;
box-shadow: 0 0 0 3px rgba(111, 193, 136, 0.22);
}
.status-dot.warn {
background: #e0b24c;
box-shadow: 0 0 0 3px rgba(224, 178, 76, 0.22);
}
.status-dot.bad {
background: #e07060;
box-shadow: 0 0 0 3px rgba(224, 112, 96, 0.22);
}
.workspace {
min-width: 0;
}
/* ========================= Top bar ================================== */
.top-bar {
position: sticky;
top: 0;
z-index: 10;
display: grid;
grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr) minmax(0, 0.85fr) minmax(0, 2fr);
align-items: stretch;
gap: 12px;
min-height: 56px;
padding: 10px 22px;
background: rgba(255, 255, 255, 0.86);
backdrop-filter: blur(12px) saturate(1.05);
-webkit-backdrop-filter: blur(12px) saturate(1.05);
border-bottom: 1px solid var(--hair);
box-shadow: 0 8px 20px -20px rgba(23, 32, 41, 0.5);
}
.toolbar input,
.toolbar select,
.manual-query-form input,
.manual-query-form select,
.candidate-collection-form input,
.candidate-collection-form select,
.collection-promotion-form input,
.collection-promotion-form select,
.collection-promotion-form textarea,
.knowledge-form input,
.knowledge-form select,
.knowledge-form textarea,
.memo-field textarea {
width: 100%;
border: 1px solid var(--hair);
border-radius: var(--r-sm);
background: var(--card-raised);
color: var(--ink);
box-shadow: var(--inset-well);
transition: border-color 140ms var(--ease), box-shadow 140ms var(--ease);
}
.toolbar input:hover,
.toolbar select:hover,
.memo-field textarea:hover,
.knowledge-form input:hover,
.knowledge-form select:hover,
.knowledge-form textarea:hover,
.manual-query-form input:hover,
.candidate-collection-form input:hover,
.collection-promotion-form input:hover,
.collection-promotion-form textarea:hover {
border-color: var(--hair-strong);
}
.toolbar input:focus,
.toolbar select:focus,
.manual-query-form input:focus,
.manual-query-form select:focus,
.candidate-collection-form input:focus,
.candidate-collection-form select:focus,
.collection-promotion-form input:focus,
.collection-promotion-form select:focus,
.collection-promotion-form textarea:focus,
.knowledge-form input:focus,
.knowledge-form select:focus,
.knowledge-form textarea:focus,
.memo-field textarea:focus {
outline: none;
border-color: var(--teal);
box-shadow: var(--inset-well), 0 0 0 3px color-mix(in srgb, var(--teal) 16%, transparent);
}
.product-purpose {
display: grid;
align-content: center;
gap: 2px;
min-width: 0;
min-height: 40px;
padding: 5px 11px 5px 12px;
border-left: 3px solid var(--teal);
border-radius: 4px;
background: var(--teal-tint);
}
.product-purpose strong {
color: var(--teal-deep);
font-size: 13px;
font-weight: 750;
letter-spacing: -0.01em;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.product-purpose span {
color: var(--ink-soft);
font-size: 11.5px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.queue-health,
.provider-pulse,
.coverage-tabs {
display: flex;
align-items: center;
gap: 8px;
min-height: 40px;
padding: 7px 11px;
overflow: hidden;
border: 1px solid var(--hair);
border-radius: var(--r-sm);
background: var(--card-raised);
color: var(--ink-soft);
font-size: 13px;
white-space: nowrap;
text-overflow: ellipsis;
box-shadow: var(--shadow-sm);
}
.coverage-tabs {
align-items: stretch;
gap: 0;
min-width: 0;
max-width: 100%;
padding: 0;
overflow: hidden;
}
.coverage-tab {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
align-items: center;
gap: 8px;
min-width: 0;
min-height: 38px;
padding: 6px 12px;
border: 0;
border-right: 1px solid var(--hair);
background: transparent;
color: var(--ink-soft);
font-size: 12px;
text-align: left;
transition: background 140ms var(--ease), color 140ms var(--ease);
}
.coverage-tab:hover {
background: var(--card-sunk);
}
.coverage-tab:last-child {
border-right: 0;
}
.coverage-tab span {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.coverage-tab strong {
color: var(--ink);
font-family: var(--font-mono);
font-size: 13px;
}
.coverage-tab.active {
background: var(--teal-deep);
color: #fff;
}
.coverage-tab.active strong {
color: #fff;
}
.coverage-tab.ok strong {
color: var(--green);
}
.coverage-tab.warn strong {
color: var(--amber);
}
.coverage-tab.bad strong {
color: var(--red);
}
.coverage-tab.active.ok strong,
.coverage-tab.active.warn strong,
.coverage-tab.active.bad strong {
color: #fff;
}
/* ========================= Main surface ============================= */
.main-surface {
padding: 24px 24px 30px;
}
.view {
display: none;
}
.view.active {
display: block;
/* Opacity-only on purpose: any transform here — even one animating toward
`none` — establishes a containing block for the whole animation and breaks
`position: fixed` on the floating decision panel inside this view. */
animation: viewRise 320ms var(--ease) backwards;
}
@keyframes viewRise {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.section-header {
display: flex;
align-items: flex-end;
justify-content: space-between;
gap: 16px;
margin-bottom: 18px;
padding-bottom: 14px;
border-bottom: 1px solid var(--hair);
}
.section-header h1 {
margin: 0;
font-size: 25px;
line-height: 1.15;
letter-spacing: -0.02em;
font-weight: 800;
}
.queue-intent {
max-width: 560px;
margin: 7px 0 0;
color: var(--ink-soft);
font-size: 13px;
line-height: 1.55;
}
/* ===================== Tabs (workbench / knowledge) ================= */
.workbench-tabs,
.knowledge-tabs {
display: flex;
flex-wrap: wrap;
gap: 4px;
margin: 0 0 16px;
border-bottom: 1px solid var(--hair);
}
.workbench-tabs button,
.knowledge-tabs button {
position: relative;
min-height: 40px;
padding: 0 16px;
border: 0;
background: transparent;
color: var(--ink-soft);
font-weight: 700;
font-size: 14px;
transition: color 140ms var(--ease);
}
.workbench-tabs button:hover,
.knowledge-tabs button:hover {
color: var(--ink);
}
.workbench-tabs button.active,
.knowledge-tabs button.active {
color: var(--teal-deep);
}
.workbench-tabs button.active::after,
.knowledge-tabs button.active::after {
content: "";
position: absolute;
left: 12px;
right: 12px;
bottom: -1px;
height: 2.5px;
border-radius: 3px;
background: var(--teal);
}
.workbench-panel,
.knowledge-panel {
display: none;
}
.workbench-panel.active,
.knowledge-panel.active {
display: block;
}
/* ===================== Queue actions ================================ */
.queue-actions {
display: flex;
flex-wrap: wrap;
gap: 8px;
justify-content: flex-end;
}
.queue-folder-input {
display: grid;
gap: 5px;
min-width: 260px;
}
.queue-file-input {
display: grid;
gap: 5px;
min-width: 190px;
cursor: pointer;
}
.queue-folder-input span,
.queue-file-input span:first-child {
color: var(--ink-faint);
font-size: 11px;
font-weight: 600;
letter-spacing: 0.07em;
text-transform: uppercase;
}
.queue-folder-input input {
min-height: 38px;
padding: 0 11px;
border: 1px solid var(--hair);
border-radius: var(--r-sm);
background: var(--card-raised);
color: var(--ink);
box-shadow: var(--inset-well);
}
.queue-file-input span:last-of-type {
display: flex;
align-items: center;
min-height: 38px;
max-width: 220px;
padding: 0 11px;
overflow: hidden;
border: 1px solid var(--hair);
border-radius: var(--r-sm);
background: var(--card-raised);
color: var(--ink-soft);
font-size: 13px;
text-overflow: ellipsis;
white-space: nowrap;
}
.queue-file-input input {
position: absolute;
width: 1px;
height: 1px;
max-width: 1px;
max-height: 1px;
overflow: hidden;
opacity: 0;
pointer-events: none;
clip: rect(0 0 0 0);
clip-path: inset(50%);
white-space: nowrap;
}
.import-status {
display: flex;
align-items: center;
gap: 8px;
min-height: 38px;
margin-bottom: 14px;
padding: 8px 12px;
border: 1px solid var(--hair);
border-radius: var(--r-sm);
background: var(--card);
color: var(--ink-soft);
font-size: 13px;
flex-wrap: wrap;
}
.intake-conflicts {
flex-basis: 100%;
padding: 8px 10px;
border: 1px solid var(--amber-line);
border-radius: var(--r-sm);
background: var(--amber-tint);
color: var(--amber);
}
.intake-conflicts ul {
margin: 6px 0 0;
padding-left: 18px;
}
/* ===================== Operator workflow strip ===================== */
.operator-workflow {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 12px;
margin: 0 0 18px;
}
.operator-workflow article {
position: relative;
display: grid;
grid-template-columns: auto minmax(0, 1fr);
gap: 4px 12px;
min-height: 84px;
padding: 15px 16px;
border: 1px solid var(--hair);
border-radius: var(--r-lg);
background: var(--card-raised);
box-shadow: var(--shadow-sm);
overflow: hidden;
}
.operator-workflow article::before {
content: "";
position: absolute;
inset: 0 auto 0 0;
width: 3px;
background: var(--teal);
opacity: 0.55;
}
.operator-workflow article span {
display: inline-grid;
place-items: center;
width: 28px;
height: 28px;
border-radius: var(--r-pill);
background: var(--teal);
color: #fff;
font-size: 13px;
font-weight: 700;
box-shadow: var(--bevel);
}
.operator-workflow strong {
align-self: center;
color: var(--ink);
font-size: 14px;
letter-spacing: -0.01em;
}
.operator-workflow p {
grid-column: 2;
margin: 0;
color: var(--ink-soft);
font-size: 12px;
line-height: 1.5;
}
.eyebrow {
margin: 0 0 6px;
color: var(--teal);
font-size: 11px;
font-weight: 600;
letter-spacing: 0.16em;
text-transform: uppercase;
}
/* ========================= Toolbar / filters ======================= */
.toolbar {
display: grid;
grid-template-columns: minmax(340px, 1.6fr) minmax(150px, 0.8fr) minmax(150px, 0.8fr) minmax(140px, 0.7fr) minmax(210px, 1fr);
gap: 12px;
align-items: end;
margin-bottom: 16px;
padding: 14px;
border: 1px solid var(--hair);
border-radius: var(--r-lg);
background: var(--card);
box-shadow: var(--shadow-sm);
}
.toolbar label,
.manual-query-form label,
.candidate-collection-form label,
.collection-promotion-form label,
.knowledge-form label,
.memo-field {
display: grid;
gap: 6px;
min-width: 0;
}
.toolbar label span,
.manual-query-form label span,
.candidate-collection-form label span,
.collection-promotion-form label span,
.knowledge-form label span,
.memo-field span {
color: var(--ink-faint);
font-size: 11px;
font-weight: 600;
letter-spacing: 0.07em;
text-transform: uppercase;
}
.toolbar input,
.toolbar select,
.manual-query-form input,
.manual-query-form select,
.candidate-collection-form input,
.candidate-collection-form select,
.collection-promotion-form input,
.collection-promotion-form select,
.knowledge-form input,
.knowledge-form select {
min-height: 38px;
padding: 0 11px;
}
.memo-field textarea,
.collection-promotion-form textarea,
.knowledge-form textarea {
min-height: 114px;
padding: 11px;
resize: vertical;
line-height: 1.5;
}
.file-picker {
cursor: pointer;
}
.file-picker-control {
display: grid;
grid-template-columns: auto minmax(0, 1fr);
gap: 8px;
align-items: center;
min-height: 38px;
padding: 5px;
border: 1px solid var(--hair);
border-radius: var(--r-sm);
background: var(--card-raised);
}
.file-picker-button {
display: inline-flex;
align-items: center;
justify-content: center;
min-height: 28px;
padding: 0 12px;
border-radius: 5px;
background: var(--teal);
color: #fff;
font-size: 13px;
font-weight: 700;
box-shadow: var(--bevel);
}
.knowledge-form .file-picker-button {
color: #fff;
}
#knowledge-image-name {
min-width: 0;
overflow: hidden;
color: var(--ink-soft);
font-size: 13px;
text-overflow: ellipsis;
white-space: nowrap;
}
.file-picker-input {
position: absolute;
width: 1px;
height: 1px;
max-width: 1px;
max-height: 1px;
overflow: hidden;
opacity: 0;
pointer-events: none;
clip: rect(0 0 0 0);
clip-path: inset(50%);
white-space: nowrap;
}
/* ========================= Segmented control ======================= */
.segmented {
display: grid;
grid-template-columns: repeat(6, minmax(0, 1fr));
min-height: 38px;
border: 1px solid var(--hair);
border-radius: var(--r-sm);
background: var(--card-raised);
overflow: hidden;
box-shadow: var(--inset-well);
}
.segmented button {
min-width: 0;
border: 0;
border-right: 1px solid var(--hair);
background: transparent;
color: var(--ink-soft);
font-size: 13px;
font-weight: 600;
overflow-wrap: anywhere;
transition: background 130ms var(--ease), color 130ms var(--ease);
}
.segmented button:hover {
background: var(--card-sunk);
color: var(--ink);
}
.segmented button:last-child {
border-right: 0;
}
.segmented button.active {
background: var(--teal-deep);
color: #fff;
}
/* ============================ Buttons =============================== */
.secondary-action,
.primary-action,
.danger-outline,
.decision-actions button,
.quick-actions button,
.icon-actions button,
.provider-actions button,
.row-action {
min-height: 36px;
border-radius: var(--r-sm);
font-weight: 700;
transition: transform 110ms var(--ease), box-shadow 140ms var(--ease),
background 140ms var(--ease), border-color 140ms var(--ease), color 140ms var(--ease);
}
.secondary-action,
.row-action,
.quick-actions button,
.icon-actions button,
.provider-actions button {
border: 1px solid var(--hair);
background: var(--card-raised);
color: var(--ink);
box-shadow: var(--shadow-sm);
}
.secondary-action:hover,
.row-action:hover,
.quick-actions button:hover,
.icon-actions button:hover,
.provider-actions button:hover {
border-color: var(--hair-strong);
background: var(--card);
transform: translateY(-1px);
}
.secondary-action:active,
.row-action:active,
.quick-actions button:active,
.icon-actions button:active,
.provider-actions button:active,
.primary-action:active,
.danger-outline:active,
.decision-actions button:active {
transform: translateY(0);
box-shadow: var(--press);
}
.row-action.active {
border-color: var(--teal);
background: var(--teal-tint);
color: var(--teal-deep);
}
.row-action.danger {
border-color: var(--red-line);
background: var(--red-tint);
color: var(--red);
}
.primary-action {
padding: 0 16px;
border: 1px solid var(--teal-deep);
background: var(--teal);
color: #fff;
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.16) inset, 0 6px 14px -10px rgba(20, 73, 92, 0.7);
}
.primary-action:hover {
background: var(--teal-deep);
transform: translateY(-1px);
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.2) inset, 0 10px 18px -10px rgba(20, 73, 92, 0.75);
}
.danger-outline {
padding: 0 16px;
border: 1px solid var(--red-line);
background: var(--red-tint);
color: var(--red);
}
.danger-outline:hover {
border-color: var(--red);
transform: translateY(-1px);
}
/* ====================== Cards / table shells ======================= */
.table-shell,
.pane,
.provider-row,
.correction-row,
.knowledge-row,
.audit-row {
border: 1px solid var(--hair);
border-radius: var(--r-lg);
background: var(--card-raised);
}
.table-shell {
overflow: visible;
box-shadow: var(--shadow);
}
table {
width: 100%;
border-collapse: collapse;
table-layout: fixed;
}
.queue-grid {
display: block;
min-width: 0;
}
.queue-grid thead {
display: block;
}
.queue-grid tbody {
display: grid;
}
.queue-grid thead tr,
.queue-row {
display: grid;
grid-template-columns: 28px 64px minmax(104px, 0.68fr) 72px minmax(126px, 0.58fr) minmax(360px, 1.5fr) 82px 76px 90px;
column-gap: 0;
align-items: center;
}
.queue-grid thead tr,
.queue-row {
width: 100%;
}
.queue-row {
min-height: 78px;
border-bottom: 1px solid var(--hair-soft);
transition: background 140ms var(--ease), box-shadow 140ms var(--ease);
}
.queue-grid tbody .queue-row:nth-child(even) {
background: rgba(240, 244, 247, 0.55);
}
.queue-row td,
.queue-grid th {
min-width: 0;
width: auto !important;
padding: 8px;
}
.queue-row td {
border-bottom: 0;
}
.queue-grid th {
position: static;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.queue-grid td {
width: auto !important;
}
.queue-row .reason-cell {
max-width: 100%;
}
.queue-submission-cell,
.queue-risk-cell,
.queue-time-cell {
min-width: 0;
}
.queue-submission-cell {
display: flex;
align-items: center;
gap: 8px;
overflow: hidden;
white-space: nowrap;
}
.queue-case-button {
display: inline-flex;
justify-content: flex-start;
justify-self: start;
width: auto;
max-width: 100%;
min-height: 32px;
padding: 4px 9px;
overflow: hidden;
white-space: nowrap;
}
.score-stack.queue-risk-cell {
display: flex;
align-items: center;
gap: 6px;
flex-wrap: nowrap;
}
.queue-risk-cell span,
.queue-time-cell,
.queue-row td:nth-child(7),
.queue-row td:nth-child(8) {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.queue-time-cell {
font-family: var(--font-mono);
font-size: 12px;
color: var(--ink-soft);
}
.queue-row td:nth-child(5),
.queue-row td:nth-child(6) {
align-self: stretch;
display: flex;
align-items: center;
}
.queue-row td:nth-child(5) {
padding-right: 6px;
}
.queue-row td:nth-child(6) {
padding-left: 6px;
align-content: center;
flex-wrap: nowrap;
gap: 3px;
}
.queue-provider-strip {
display: flex;
flex-wrap: nowrap;
gap: 3px;
min-width: 0;
max-width: 100%;
overflow: hidden;
}
.queue-provider-chip {
flex: 0 0 auto;
min-width: 0;
margin: 0;
padding-inline: 6px;
font-size: 11px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
th,
td {
padding: 10px;
border-bottom: 1px solid var(--hair-soft);
text-align: left;
vertical-align: middle;
}
th {
position: sticky;
top: 0;
z-index: 1;
background: var(--card-sunk);
color: var(--ink-faint);
font-size: 11px;
font-weight: 600;
letter-spacing: 0.08em;
text-transform: uppercase;
border-bottom: 1px solid var(--hair);
}
td {
color: var(--ink);
font-size: 13px;
}
tbody tr {
transition: background 140ms var(--ease), box-shadow 140ms var(--ease);
}
tbody tr:hover {
background: var(--teal-tint);
}
.queue-grid tbody .queue-row:hover {
background: var(--teal-tint);
}
/* Selection must outrank the zebra stripe (.queue-grid tbody
.queue-row:nth-child(even), specificity 0,3,1) on even rows. */
tbody tr.selected-row,
.queue-grid tbody .queue-row.selected-row {
box-shadow: inset 4px 0 0 var(--teal), var(--shadow-sm);
background: var(--teal-tint-soft);
}
.thumb {
width: 62px;
height: 48px;
border: 1px solid var(--hair);
border-radius: var(--r-sm);
background: var(--card-sunk);
object-fit: cover;
box-shadow: var(--shadow-sm);
}
.submission-id {
display: block;
min-width: 0;
overflow: hidden;
font-family: var(--font-mono);
font-weight: 700;
font-size: 12.5px;
letter-spacing: -0.01em;
text-overflow: ellipsis;
white-space: nowrap;
}
.muted {
color: var(--ink-soft);
}
.small {
font-size: 12px;
}
.score-stack {
display: grid;
gap: 4px;
}
/* =========================== Pills & chips ========================= */
.score-pill,
.risk-badge,
.source-chip,
.decision-badge,
.provider-chip,
.provenance-chip,
.evidence-status-chip,
.watchlist-chip {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 5px;
max-width: 100%;
min-height: 24px;
padding: 3px 9px;
border-radius: var(--r-pill);
border: 1px solid transparent;
font-size: 12px;
font-weight: 700;
line-height: 1.2;
overflow-wrap: anywhere;
}
.score-pill,
.risk-badge {
font-family: var(--font-mono);
font-weight: 700;
letter-spacing: -0.01em;
}
.risk-high {
border-color: var(--red-line);
background: var(--red-tint);
color: var(--red);
}
.source-chip {
flex: 0 0 auto;
white-space: nowrap;
}
/* Publishing host. Monospace so hostnames align down a long evidence list and
near-identical domains (cdn.example.com vs cdn-example.com) separate at a
glance; quieter than the source chip because it sits next to it on every row
and two competing chips would flatten the hierarchy. */
/* A retained case whose source file is gone. The image cannot be served, so the
frame says so instead of leaving a silently broken thumbnail: the row is still
the record of a real decision and has to stay legible as one. */
.thumb-missing,
.case-image-missing {
outline: 2px dashed var(--amber-line);
outline-offset: 2px;
opacity: 0.55;
}
.host-chip {
/* Bounded, then rigid. Bounded because CDN hostnames run past 45 characters
and an unbounded chip ate the whole title line, leaving the headline to
wrap one character per row. Rigid within that bound because the title beside
it is boilerplate ("구글 full image match found" on every row) while this is
the row's actual content — a host short enough to fit must never be the
thing that gets truncated. */
flex: 0 0 auto;
max-width: 20ch;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-family: var(--font-mono);
font-size: 12px;
font-weight: 600;
letter-spacing: 0;
color: var(--ink-soft);
}
.evidence-status-chip,
.watchlist-chip.watchlist {
border-color: var(--amber-line);
background: var(--amber-tint);
color: var(--amber);
}
.watchlist-chip.confirmed {
border-color: var(--green-line);
background: var(--green-tint);
color: var(--green);
}
.watchlist-chip.excluded {
border-color: #d6cbd2;
background: #f2eef1;
color: var(--ink-soft);
}
.risk-medium {
border-color: var(--amber-line);
background: var(--amber-tint);
color: var(--amber);
}
.risk-low {
border-color: var(--green-line);
background: var(--green-tint);
color: var(--green);
}
.risk-failed {
border-color: var(--violet-line);
background: var(--violet-tint);
color: var(--violet);
}
.risk-pending {
border-color: var(--blue-line);
background: var(--blue-tint);
color: var(--blue);
}
.source-naver {
border-color: var(--forest-line);
background: var(--forest-tint);
color: var(--forest);
}
.source-google {
border-color: var(--blue-line);
background: var(--blue-tint);
color: var(--blue);
}
.source-llm {
border-color: var(--violet-line);
background: var(--violet-tint);
color: var(--violet);
}
.source-internal {
border-color: var(--slate-line);
background: var(--slate-tint);
color: var(--slate);
}
.source-failure {
border-color: var(--red-line);
background: var(--red-tint);
color: var(--red);
}
.provider-chip {
margin: 1px 2px 1px 0;
border-color: var(--hair);
background: var(--card-sunk);
color: var(--ink-soft);
letter-spacing: 0.02em;
}
.provider-chip.ok {
border-color: var(--green-line);
background: var(--green-tint);
color: var(--green);
}
.provider-chip.failed {
border-color: var(--red-line);
background: var(--red-tint);
color: var(--red);
}
.provider-chip.disabled,
.provider-chip.skipped {
border-color: var(--hair-strong);
color: var(--ink-soft);
}
.reason-cell {
display: flex;
flex-wrap: nowrap;
gap: 4px;
min-width: 0;
overflow: hidden;
}
.reason-cell span {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* ========================= Case layout ============================= */
.case-layout {
display: grid;
grid-template-columns: minmax(270px, 0.9fr) minmax(360px, 1.3fr) minmax(288px, 0.82fr);
gap: 16px;
align-items: start;
}
.evidence-layout {
grid-template-columns: minmax(280px, 0.72fr) minmax(0, 1fr);
padding-bottom: 260px;
}
.evidence-layout .decision-pane {
grid-column: auto;
}
.pane {
min-width: 0;
padding: 16px;
box-shadow: var(--shadow-sm);
}
.pane-heading {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
margin-bottom: 14px;
padding-bottom: 11px;
border-bottom: 1px solid var(--hair-soft);
}
.pane-heading.vertical {
display: block;
}
.pane-heading h2 {
margin: 0;
font-size: 16px;
line-height: 1.25;
letter-spacing: -0.01em;
}
.icon-actions {
display: flex;
gap: 6px;
}
.icon-actions button {
width: 44px;
padding: 0 6px;
font-size: 12px;
}
.review-image-frame {
margin: 0;
position: relative;
}
.review-image-frame img {
display: block;
width: 100%;
aspect-ratio: 4 / 3;
border: 1px solid var(--hair);
border-radius: var(--radius);
background: var(--card-sunk);
object-fit: cover;
box-shadow: var(--shadow-sm);
}
.review-image-frame figcaption {
min-height: 18px;
margin-top: 7px;
color: var(--ink-soft);
font-size: 12px;
}
.fact-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 8px;
margin-top: 14px;
}
.fact-item {
min-height: 54px;
padding: 9px 10px;
border: 1px solid var(--hair-soft);
border-radius: var(--r-sm);
background: var(--card);
}
.fact-item span {
display: block;
color: var(--ink-faint);
font-size: 10px;
font-weight: 600;
letter-spacing: 0.07em;
text-transform: uppercase;
}
.fact-item strong {
display: block;
margin-top: 5px;
font-family: var(--font-mono);
font-size: 13px;
overflow-wrap: anywhere;
}
.similar-strip {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 8px;
margin-top: 14px;
}
.similar-item {
display: grid;
gap: 5px;
min-width: 0;
}
.similar-item img {
width: 100%;
aspect-ratio: 4 / 3;
border: 1px solid var(--hair);
border-radius: var(--r-sm);
object-fit: cover;
}
.similar-item span {
color: var(--ink-soft);
font-size: 12px;
overflow-wrap: anywhere;
}
.reason-list {
display: grid;
gap: 12px;
margin-bottom: 12px;
}
.evidence-summary-board {
display: grid;
gap: 12px;
padding: 14px;
border: 1px solid var(--hair);
border-radius: var(--radius);
background: var(--card);
}
.summary-lead {
display: grid;
grid-template-columns: auto minmax(0, 1fr);
gap: 10px;
align-items: center;
}
.summary-lead strong {
display: block;
font-size: 17px;
line-height: 1.35;
letter-spacing: -0.01em;
/* 한 줄 요약은 "라벨 10개" 같은 구를 줄 사이에서 쪼개지 않는다 — 구분점(·) 단위로만 접힌다. */
word-break: keep-all;
}
.summary-lead span:not(.risk-badge) {
display: block;
margin-top: 3px;
color: var(--ink-soft);
font-size: 12px;
}
.summary-stat-grid {
display: grid;
grid-template-columns: repeat(6, minmax(0, 1fr));
gap: 8px;
}
.summary-stat {
min-width: 0;
padding: 9px 10px;
border: 1px solid var(--hair-soft);
border-radius: var(--r-sm);
background: var(--card-raised);
}
.summary-stat.has-signal {
border-color: var(--ochre-line);
background: var(--ochre-tint);
}
.summary-stat span {
display: block;
color: var(--ink-faint);
font-size: 10px;
font-weight: 600;
letter-spacing: 0.06em;
text-transform: uppercase;
}
.summary-stat strong {
display: block;
margin-top: 3px;
font-family: var(--font-mono);
font-size: 19px;
letter-spacing: -0.02em;
}
.evidence-groups {
display: grid;
gap: 14px;
}
.evidence-next-actions {
margin-bottom: 12px;
}
.evidence-next-action-panel {
display: grid;
gap: 10px;
padding: 14px;
border: 1px solid var(--ochre-line);
border-left: 3px solid var(--ochre);
border-radius: var(--radius);
background: var(--ochre-tint);
}
.evidence-next-action-panel strong,
.evidence-next-action-panel span {
display: block;
}
.evidence-next-action-panel strong {
letter-spacing: -0.01em;
}
.evidence-next-action-panel span {
margin-top: 3px;
color: var(--ink-soft);
font-size: 12px;
}
.evidence-followup-reasons {
display: grid;
gap: 4px;
margin: 0;
padding-left: 18px;
color: var(--ink-soft);
font-size: 13px;
}
.suggested-query-list {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.evidence-group {
display: grid;
gap: 10px;
min-width: 0;
padding: 12px;
border: 1px solid var(--hair);
border-radius: var(--radius);
background: var(--card-raised);
}
.evidence-group-strong {
border-color: var(--ochre-line);
background: var(--ochre-tint-soft);
box-shadow: 0 0 0 1px rgba(176, 125, 24, 0.08);
}
.evidence-group-weak {
background: var(--card);
}
.evidence-group-head {
display: flex;
align-items: start;
justify-content: space-between;
gap: 10px;
}
.evidence-group h3 {
margin: 0;
color: var(--ink);
font-size: 15px;
letter-spacing: -0.01em;
}
.evidence-group-head span {
display: block;
margin-top: 3px;
color: var(--ink-soft);
font-size: 12px;
}
.evidence-group-head strong {
flex: 0 0 auto;
min-width: 42px;
padding: 4px 9px;
border: 1px solid var(--hair);
border-radius: var(--r-pill);
background: var(--card);
font-family: var(--font-mono);
font-size: 12px;
text-align: center;
}
.evidence-card-grid {
display: grid;
grid-template-columns: 1fr;
gap: 9px;
}
.evidence-details {
display: grid;
gap: 9px;
}
.evidence-details summary {
cursor: pointer;
width: max-content;
max-width: 100%;
padding: 7px 12px;
border: 1px solid var(--hair);
border-radius: var(--r-sm);
background: var(--card-sunk);
color: var(--ink);
font-size: 13px;
font-weight: 700;
transition: background 130ms var(--ease), border-color 130ms var(--ease);
}
.evidence-details summary:hover {
border-color: var(--hair-strong);
background: var(--card);
}
.evidence-details[open] summary {
margin-bottom: 9px;
}
.evidence-card-grid-detail {
padding-top: 0;
}
.evidence-row,
.query-row,
.result-row,
.knowledge-row,
.correction-row,
.provider-row {
display: grid;
gap: 8px;
min-width: 0;
padding: 12px;
border: 1px solid var(--hair);
border-radius: var(--radius);
background: var(--card);
}
.evidence-row {
grid-template-columns: 118px minmax(0, 1fr) auto;
align-items: start;
background: var(--card-raised);
}
.evidence-row.no-preview {
grid-template-columns: minmax(0, 1fr) auto;
}
.evidence-main {
min-width: 0;
}
.evidence-preview {
display: block;
width: 118px;
min-width: 118px;
align-self: start;
}
.evidence-preview-empty {
display: none;
}
.evidence-preview img {
display: block;
width: 118px;
aspect-ratio: 1 / 1;
border: 1px solid var(--hair);
border-radius: var(--r-sm);
background: var(--card-raised);
object-fit: cover;
}
.evidence-link {
display: inline-block;
max-width: 100%;
margin-top: 7px;
color: var(--blue);
font-family: var(--font-mono);
font-size: 12px;
font-weight: 700;
overflow-wrap: anywhere;
text-decoration-color: rgba(44, 87, 138, 0.35);
text-underline-offset: 2px;
}
.evidence-link:hover {
text-decoration-color: currentColor;
}
.evidence-title,
.row-title {
display: flex;
/* Wraps because the chips beside the title do not. source-chip and host-chip
are both rigid, and at phone width they leave the headline a few dozen
pixels - which `overflow-wrap: anywhere` below then honours by breaking it
one character per row. With wrapping the title drops to its own line
intact, and desktop layout is unchanged because nothing overflows there. */
flex-wrap: wrap;
align-items: center;
gap: 7px;
min-width: 0;
font-weight: 700;
letter-spacing: -0.01em;
}
.evidence-title span:last-child,
.row-title span:last-child {
min-width: 0;
overflow-wrap: anywhere;
}
/* The title claims the space the chips beside it do not, so `overflow-wrap:
anywhere` above stays a wrapping rule and never becomes a one-character
column. The floor is what makes the container's `flex-wrap` fire: without it
the title shrinks to the residue left by the chips instead of moving to the
next line. */
.evidence-title > span:last-child {
flex: 1 1 auto;
min-width: 14ch;
}
.evidence-meta,
.row-meta {
display: flex;
flex-wrap: wrap;
gap: 6px 10px;
margin-top: 5px;
color: var(--ink-soft);
font-size: 12px;
}
.evidence-actions {
display: flex;
flex-direction: column;
gap: 6px;
align-items: flex-end;
}
.knowledge-row.watchlist {
border-color: var(--ochre-line);
background: var(--ochre-tint-soft);
}
/* ===================== Decision pane / floating ==================== */
.recommendation-box {
display: grid;
gap: 8px;
margin-bottom: 14px;
padding: 13px;
border: 1px solid var(--hair);
border-radius: var(--radius);
background: var(--card);
}
.recommendation-box strong {
font-size: 18px;
letter-spacing: -0.01em;
}
.floating-decision-panel {
position: fixed;
right: 24px;
bottom: 24px;
z-index: 20;
width: min(310px, calc(100vw - 48px));
max-height: calc(100vh - 132px);
overflow: auto;
border-radius: var(--r-lg);
background: var(--card-raised);
box-shadow: var(--shadow-lg);
animation: panelIn 360ms var(--ease) both;
}
@keyframes panelIn {
from {
opacity: 0;
transform: translateY(14px) scale(0.985);
}
to {
opacity: 1;
transform: none;
}
}
.floating-decision-head {
margin-bottom: 10px;
}
.floating-decision-panel .recommendation-box {
margin-bottom: 10px;
padding: 11px;
}
.floating-decision-panel .recommendation-box strong {
font-size: 15px;
}
.floating-decision-panel .memo-field textarea {
min-height: 76px;
}
.form-error {
min-height: 18px;
margin: 6px 0 8px;
color: var(--red);
font-size: 12px;
font-weight: 700;
}
.decision-actions {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 8px;
}
.decision-secondary {
margin-top: 10px;
}
.decision-secondary summary {
cursor: pointer;
color: var(--ink-soft);
font-size: 11px;
font-weight: 600;
letter-spacing: 0.07em;
text-transform: uppercase;
}
.approve-action {
border: 1px solid var(--green-line);
background: var(--green-tint);
color: var(--green);
}
.approve-action:hover {
border-color: var(--green);
transform: translateY(-1px);
}
.hold-action {
border: 1px solid var(--amber-line);
background: var(--amber-tint);
color: var(--amber);
}
.hold-action:hover {
border-color: var(--amber);
transform: translateY(-1px);
}
.reject-action {
border: 1px solid var(--red-line);
background: var(--red-tint);
color: var(--red);
}
.reject-action:hover {
border-color: var(--red);
transform: translateY(-1px);
}
.derived-preview {
display: grid;
gap: 6px;
margin-top: 12px;
padding: 11px;
border: 1px solid var(--hair-soft);
border-radius: var(--r-sm);
background: var(--card-sunk);
font-size: 13px;
}
.quick-actions {
display: grid;
grid-template-columns: 1fr;
gap: 8px;
margin-top: 12px;
}
.quick-actions button {
width: 100%;
}
/* ===================== Split workspace / forms ===================== */
.split-workspace {
display: grid;
grid-template-columns: minmax(280px, 0.85fr) minmax(420px, 1.15fr);
gap: 16px;
align-items: start;
}
.manual-query-form,
.candidate-collection-form,
.collection-promotion-form,
.knowledge-form {
display: grid;
gap: 12px;
margin-bottom: 16px;
}
.manual-query-form {
grid-template-columns: minmax(160px, 0.4fr) minmax(240px, 1fr) auto;
align-items: end;
}
.candidate-collection-form {
grid-template-columns: minmax(120px, 0.35fr) minmax(220px, 1fr) auto;
align-items: end;
}
.collection-promotion-form {
grid-template-columns: minmax(160px, 1fr) minmax(140px, 0.7fr);
align-items: end;
padding-top: 2px;
}
.collection-promotion-form .wide-field {
grid-column: 1 / -1;
}
.collection-promotion-form button {
justify-self: start;
}
.candidate-selection-actions {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin: 2px 0 10px;
}
.collection-candidates {
display: grid;
gap: 8px;
margin-bottom: 14px;
}
.candidate-card {
display: grid;
grid-template-columns: auto 74px minmax(0, 1fr) auto;
gap: 10px;
align-items: center;
padding: 10px;
border: 1px solid var(--hair);
border-radius: var(--radius);
background: var(--card);
transition: border-color 140ms var(--ease), box-shadow 140ms var(--ease);
}
.candidate-card:hover {
border-color: var(--hair-strong);
box-shadow: var(--shadow-sm);
}
.candidate-actions {
display: grid;
gap: 6px;
justify-items: stretch;
align-self: center;
}
.candidate-card.promoted {
background: var(--card-sunk);
}
.candidate-select {
display: grid;
place-items: center;
width: 26px;
min-height: 38px;
}
.candidate-select input {
width: 18px;
height: 18px;
accent-color: var(--teal);
}
.candidate-thumb {
width: 74px;
aspect-ratio: 1;
border: 1px solid var(--hair);
border-radius: var(--r-sm);
background: var(--card-sunk);
object-fit: cover;
}
.candidate-thumb.empty {
background: var(--card-sunk);
}
.candidate-main {
min-width: 0;
}
.compact-heading {
margin-top: 4px;
margin-bottom: 8px;
}
.section-divider {
height: 1px;
margin: 16px 0;
background: var(--hair);
}
.inline-status {
min-height: 20px;
margin-bottom: 10px;
color: var(--ink-soft);
font-size: 13px;
}
.stack-list {
display: grid;
gap: 10px;
}
/* ========================= Knowledge rows ========================== */
.knowledge-row {
grid-template-columns: 72px minmax(0, 1fr) minmax(128px, auto);
grid-template-areas: "thumb main actions";
align-items: start;
background: var(--card-raised);
}
.knowledge-row.inactive,
.correction-row.inactive {
background: var(--card-sunk);
color: var(--ink-soft);
}
.knowledge-thumb {
grid-area: thumb;
width: 72px;
aspect-ratio: 1;
border: 1px solid var(--hair);
border-radius: var(--r-sm);
background: var(--card-sunk);
object-fit: cover;
}
.knowledge-thumb.empty {
background: var(--card-sunk);
}
.knowledge-main {
grid-area: main;
display: grid;
gap: 7px;
min-width: 0;
}
.knowledge-title {
font-size: 15px;
letter-spacing: -0.01em;
}
.knowledge-detail-line {
display: flex;
align-items: center;
gap: 8px 12px;
min-width: 0;
white-space: nowrap;
overflow: hidden;
}
.knowledge-chip-row {
display: flex;
flex: 0 0 auto;
flex-wrap: nowrap;
gap: 6px;
align-items: center;
}
.knowledge-chip-row .provenance-chip,
.knowledge-chip-row .watchlist-chip {
flex: 0 0 auto;
white-space: nowrap;
}
.knowledge-meta {
flex: 1 1 auto;
align-items: center;
gap: 5px 12px;
min-width: 0;
margin-top: 0;
overflow: hidden;
white-space: nowrap;
}
.knowledge-meta span {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.knowledge-actions {
grid-area: actions;
display: flex;
flex-direction: column;
gap: 6px;
align-items: stretch;
min-width: 128px;
}
.chip-row {
display: flex;
flex-wrap: wrap;
gap: 6px;
}
.provenance-chip.manual {
border-color: var(--teal-line);
background: var(--teal-tint);
color: var(--teal);
}
.provenance-chip.automatic {
border-color: var(--ochre-line);
background: var(--ochre-tint);
color: var(--amber);
}
.correction-row {
grid-template-columns: minmax(0, 1fr) auto;
}
/* ========================= Providers =============================== */
.provider-list {
display: grid;
gap: 12px;
}
.provider-row {
grid-template-columns: minmax(0, 1fr) minmax(240px, 0.45fr) auto;
align-items: center;
background: var(--card-raised);
}
.provider-summary {
display: grid;
gap: 6px;
}
.quota-meter {
height: 9px;
border-radius: var(--r-pill);
background: var(--paper-2);
overflow: hidden;
box-shadow: inset 0 1px 2px rgba(23, 32, 41, 0.12);
}
.quota-meter span {
display: block;
height: 100%;
border-radius: inherit;
background: var(--teal);
transition: width 600ms var(--ease);
}
.provider-actions {
display: flex;
gap: 8px;
}
/* ========================= Audit table ============================= */
.audit-table th:nth-child(1),
.audit-table td:nth-child(1) {
width: 168px;
}
.audit-table td:nth-child(1) {
font-family: var(--font-mono);
font-size: 12px;
color: var(--ink-soft);
}
.audit-table th:nth-child(2),
.audit-table td:nth-child(2) {
width: 120px;
}
.audit-table th:nth-child(3),
.audit-table td:nth-child(3) {
width: 172px;
}
.audit-table th:nth-child(4),
.audit-table td:nth-child(4) {
width: var(--audit-object-width);
}
.audit-table th:nth-child(5),
.audit-table td:nth-child(5) {
width: var(--audit-object-width);
}
.empty-state {
display: grid;
place-items: center;
min-height: 94px;
padding: 20px;
border: 1px dashed var(--hair-strong);
border-radius: var(--radius);
background: var(--card-sunk);
color: var(--ink-soft);
text-align: center;
}
/* ===================== Page-load choreography ====================== */
@media (prefers-reduced-motion: no-preference) {
.nav-button {
animation: railIn 460ms var(--ease) both;
}
.nav-button:nth-of-type(1) { animation-delay: 60ms; }
.nav-button:nth-of-type(2) { animation-delay: 110ms; }
.nav-button:nth-of-type(3) { animation-delay: 160ms; }
.nav-button:nth-of-type(4) { animation-delay: 210ms; }
.nav-button:nth-of-type(5) { animation-delay: 260ms; }
.operator-workflow article {
animation: railIn 500ms var(--ease) both;
}
.operator-workflow article:nth-child(1) { animation-delay: 120ms; }
.operator-workflow article:nth-child(2) { animation-delay: 190ms; }
.operator-workflow article:nth-child(3) { animation-delay: 260ms; }
}
@keyframes railIn {
from {
opacity: 0;
transform: translateX(-7px);
}
to {
opacity: 1;
transform: none;
}
}
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.001ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.001ms !important;
scroll-behavior: auto !important;
}
}
/* ============================ Responsive =========================== */
@media (min-width: 1181px) {
.workbench-panel[data-workbench-panel="evidence"] {
padding-right: 334px;
}
}
@media (max-width: 1380px) {
/* The 5-track toolbar needs ~1364px of viewport (track minimums + rail +
paddings); collapse it before that point, not at the generic 1180px step. */
.toolbar {
grid-template-columns: 1fr 1fr 1fr;
}
.filter-search {
grid-column: span 2;
}
}
@media (max-width: 1180px) {
.case-layout {
grid-template-columns: minmax(280px, 0.9fr) minmax(360px, 1.1fr);
}
.decision-pane {
grid-column: 1 / -1;
}
.floating-decision-panel {
grid-column: auto;
}
}
@media (max-width: 980px) {
.app-shell {
grid-template-columns: 1fr;
}
.nav-rail {
position: static;
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
height: auto;
padding: 12px;
}
.brand-block,
.nav-footer {
grid-column: 1 / -1;
}
.brand-block {
margin-bottom: 6px;
padding-bottom: 10px;
}
.nav-button.active::before {
left: 0;
top: auto;
bottom: -2px;
width: 100%;
height: 3px;
transform: none;
border-radius: 3px 3px 0 0;
}
.top-bar {
grid-template-columns: 1fr;
align-items: stretch;
}
.product-purpose,
.queue-health,
.provider-pulse,
.coverage-tabs {
min-width: 0;
width: 100%;
white-space: normal;
}
.product-purpose strong,
.product-purpose span {
white-space: normal;
}
.coverage-tabs {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
overflow: hidden;
}
.case-layout,
.operator-workflow,
.split-workspace,
.provider-row {
grid-template-columns: 1fr;
}
.evidence-layout {
padding-bottom: 300px;
}
.summary-stat-grid {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
}
@media (max-width: 680px) {
.main-surface {
padding: 14px;
}
.section-header {
display: grid;
align-items: start;
}
.toolbar,
.manual-query-form,
.candidate-collection-form,
.collection-promotion-form {
grid-template-columns: 1fr;
}
.segmented {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.nav-rail {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.decision-actions,
.fact-grid,
.similar-strip,
.summary-stat-grid {
grid-template-columns: 1fr;
}
.floating-decision-panel {
right: 10px;
bottom: 10px;
width: calc(100vw - 20px);
max-height: 46vh;
padding: 10px;
}
.floating-decision-panel .decision-actions {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
.floating-decision-panel .memo-field textarea {
min-height: 58px;
}
.evidence-row,
.evidence-row.no-preview,
.candidate-card {
grid-template-columns: 1fr;
}
.knowledge-detail-line,
.knowledge-meta {
flex-wrap: wrap;
white-space: normal;
}
.knowledge-row {
grid-template-columns: 56px minmax(0, 1fr);
grid-template-areas:
"thumb main"
"actions actions";
}
.knowledge-thumb {
width: 56px;
}
.knowledge-actions {
min-width: 0;
}
.evidence-preview,
.evidence-preview img,
.candidate-thumb {
width: 100%;
min-width: 0;
}
.evidence-actions {
flex-direction: row;
align-items: stretch;
}
th,
td {
padding: 8px;
}
.table-shell {
overflow: visible;
box-shadow: none;
}
.queue-table,
.queue-table tbody,
.queue-table tr,
.queue-table td {
display: block;
width: 100%;
}
.queue-table thead {
display: none;
}
.queue-table tbody {
display: grid;
gap: 10px;
}
.queue-table tr {
display: grid;
grid-template-columns: 24px 72px minmax(0, 1fr);
gap: 8px 10px;
align-items: start;
padding: 12px;
border: 1px solid var(--hair);
border-radius: var(--radius);
background: var(--card-raised);
box-shadow: var(--shadow-sm);
}
.queue-table td {
min-width: 0;
padding: 0;
border-bottom: 0;
}
.queue-table td:nth-child(1) {
grid-column: 1;
grid-row: 1;
align-self: center;
}
.queue-table td:nth-child(2) {
grid-column: 2;
grid-row: 1 / span 2;
}
.queue-table td:nth-child(3) {
grid-column: 3;
grid-row: 1;
}
.queue-table td:nth-child(4) {
grid-column: 3;
grid-row: 2;
}
.queue-table td:nth-child(5),
.queue-table td:nth-child(6),
.queue-table td:nth-child(7),
.queue-table td:nth-child(8),
.queue-table td:nth-child(9) {
grid-column: 1 / -1;
}
.queue-table td:nth-child(7),
.queue-table td:nth-child(8),
.queue-table td:nth-child(9) {
display: grid;
grid-template-columns: 58px minmax(0, 1fr);
gap: 6px;
color: var(--ink-soft);
font-size: 12px;
}
.queue-table td:nth-child(7)::before {
content: "지원자";
font-weight: 700;
}
.queue-table td:nth-child(8)::before {
content: "판정";
font-weight: 700;
}
.queue-table td:nth-child(9)::before {
content: "시간";
font-weight: 700;
}
.queue-table .thumb {
width: 72px;
height: 56px;
}
.queue-table .row-action {
max-width: 100%;
height: auto;
min-height: 34px;
overflow-wrap: anywhere;
white-space: normal;
}
.queue-table .submission-id {
overflow-wrap: anywhere;
}
.audit-table,
.audit-table tbody,
.audit-table tr,
.audit-table td {
display: block;
width: 100% !important;
}
.audit-table thead {
display: none;
}
.audit-table tbody {
display: grid;
gap: 10px;
}
.audit-table tr {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 6px 10px;
padding: 12px;
border: 1px solid var(--hair);
border-radius: var(--radius);
background: var(--card-raised);
box-shadow: var(--shadow-sm);
}
.audit-table td {
min-width: 0;
padding: 0;
border-bottom: 0;
overflow-wrap: anywhere;
}
.audit-table td:nth-child(1),
.audit-table td:nth-child(2),
.audit-table td:nth-child(3) {
grid-column: 1 / -1;
}
.audit-table td:nth-child(4),
.audit-table td:nth-child(5) {
grid-column: auto;
}
}
.suggested-query-item {
display: inline-flex;
gap: 4px;
align-items: center;
}
.suggested-query-actions {
margin-top: 8px;
}
.knowledge-filter-bar {
display: flex;
flex-wrap: wrap;
gap: 8px 12px;
margin-bottom: 12px;
}
.knowledge-edit-form {
display: grid;
gap: 8px;
margin-top: 8px;
padding: 10px;
border: 1px solid var(--hair);
border-radius: 8px;
}
.knowledge-edit-actions {
display: flex;
gap: 8px;
}
.face-crop-strip .face-crop-item img {
border: 1px solid var(--hair);
border-radius: 6px;
}
.rerun-diff-panel {
display: flex;
flex-wrap: wrap;
gap: 8px 16px;
align-items: center;
padding: 10px 12px;
border: 1px solid var(--hair);
border-radius: 8px;
margin-bottom: 12px;
}
.evidence-new-chip {
border: 1px solid var(--teal);
border-radius: 999px;
padding: 0 8px;
font-size: 12px;
color: var(--teal);
}
.evidence-row-new {
box-shadow: inset 0 0 0 2px var(--teal);
}
/* --- Auth gate ------------------------------------------------------- */
/* Shown only when the server runs with COPYRIGHTER_AUTH_TOKEN and a data
route answered 401. Covers the shell so no half-loaded queue is visible
behind it. */
.auth-gate {
position: fixed;
inset: 0;
z-index: 100;
display: grid;
place-items: center;
padding: 24px;
background: rgba(16, 23, 29, 0.55);
backdrop-filter: blur(2px);
}
.auth-gate[hidden] {
display: none;
}
.auth-gate-card {
width: min(420px, 100%);
display: flex;
flex-direction: column;
gap: 10px;
padding: 26px 26px 22px;
background: var(--card-raised);
border: 1px solid var(--hair);
border-radius: var(--r-lg);
box-shadow: var(--shadow-lg);
}
.auth-gate-card h1 {
margin: 0;
font-size: 1.05rem;
letter-spacing: -0.01em;
color: var(--ink);
}
.auth-gate-hint {
margin: 0;
font-size: 0.82rem;
line-height: 1.55;
color: var(--ink-soft);
}
.auth-gate-hint code {
font-family: var(--font-mono);
font-size: 0.78rem;
padding: 1px 5px;
border-radius: var(--r-sm);
background: var(--card-sunk);
border: 1px solid var(--hair-soft);
}
.auth-gate-label {
margin-top: 4px;
font-size: 0.75rem;
font-weight: 600;
letter-spacing: 0.02em;
color: var(--ink-soft);
}
.auth-gate-input {
width: 100%;
padding: 9px 11px;
font-family: var(--font-mono);
font-size: 0.86rem;
color: var(--ink);
background: var(--card);
border: 1px solid var(--hair-strong);
border-radius: var(--radius);
}
.auth-gate-input:focus {
outline: 2px solid var(--teal-line);
outline-offset: 1px;
border-color: var(--teal);
}
.auth-gate-error {
margin: 0;
font-size: 0.78rem;
color: var(--red);
}
.auth-gate-error[hidden] {
display: none;
}
.auth-gate-card .primary-action {
margin-top: 6px;
justify-content: center;
}
/* --- Batch decisions / review throughput ------------------------------ */
.queue-actions-secondary {
margin-top: 8px;
padding-top: 8px;
border-top: 1px dashed var(--hair);
align-items: center;
}
.bulk-decision-label {
font-size: 0.78rem;
font-weight: 600;
color: var(--ink-soft);
font-variant-numeric: tabular-nums;
}
.review-progress {
margin-left: auto;
font-size: 0.76rem;
color: var(--ink-faint);
font-variant-numeric: tabular-nums;
}
.keyboard-help {
margin: 8px 0 0;
padding: 12px 14px;
font-family: var(--font-mono);
font-size: 0.78rem;
line-height: 1.7;
color: var(--ink-soft);
background: var(--card-sunk);
border: 1px solid var(--hair);
border-radius: var(--radius);
white-space: pre;
overflow-x: auto;
}
.keyboard-help[hidden] {
display: none;
}
/* --- Decision memo presets -------------------------------------------- */
.memo-presets {
display: flex;
flex-wrap: wrap;
gap: 5px;
margin-top: 6px;
}
.memo-preset-chip {
padding: 3px 9px;
font-size: 0.74rem;
color: var(--ink-soft);
background: var(--card-sunk);
border: 1px solid var(--hair);
border-radius: var(--r-pill);
cursor: pointer;
}
.memo-preset-chip:hover {
color: var(--teal-deep);
border-color: var(--teal-line);
background: var(--teal-tint-soft);
}
.memo-preset-add {
border-style: dashed;
color: var(--ink-faint);
}
/* --- Duplicate group badge -------------------------------------------- */
/* 동일 이미지 선례. 판정 버튼 바로 위에 서서 "이건 이미 판정한 이미지"를
먼저 읽게 한다 — 이 정보는 원래 큐 배지의 title 에만 있어 마우스를 올린
사람만 볼 수 있었다. */
.prior-decision {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px;
margin-top: 8px;
padding: 8px 10px;
border: 1px solid var(--green-line);
border-radius: 8px;
background: var(--green-tint);
font-size: 0.82rem;
}
.prior-decision strong {
color: var(--green);
}
/* 판정 불일치는 승계를 제안하지 않는 상태다. 같은 초록으로 두면 "정리된 것"으로
읽히므로 색을 갈라 운영자가 직접 봐야 하는 신호임을 드러낸다. */
.prior-decision:has(.prior-decision-conflict) {
border-color: var(--amber-line);
background: var(--amber-tint);
}
.prior-decision-conflict {
color: var(--amber);
}
/* 그룹 헤더의 개수와 일괄 액션. 개수 옆에 두어 "이 51건을 한 번에"가 한 시선에
읽히게 한다 — 행마다 누르던 노동이 여기서 없어진다. */
/* 점수 구성. 증거 목록과 점수 사이의 간극을 메우는 자리라, 증거 요약 바로
아래에 둔다. */
/* 반려 사유 선택. 승인·보류가 1타인데 반려만 마우스로 끝나던 비대칭을 없앤다 —
법적으로 가장 중요한 경로가 가장 느릴 이유가 없다. */
.reject-prompt {
margin-top: 8px;
padding: 8px 10px;
border: 1px solid var(--red-line);
border-radius: 8px;
background: var(--red-tint);
font-size: 0.8rem;
}
.reject-prompt ol {
margin: 6px 0;
padding: 0;
list-style: none;
}
.reject-prompt li {
display: flex;
align-items: center;
gap: 6px;
padding: 2px 0;
}
/* 화면의 번호가 곧 단축키다. 눌러야 할 키를 키처럼 보이게 한다. */
.memo-preset-key {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 16px;
height: 16px;
margin-right: 4px;
padding: 0 3px;
border: 1px solid var(--rail-ink);
border-radius: 3px;
background: var(--rail-ink-strong);
font-family: var(--font-mono);
font-size: 0.68rem;
color: var(--ink-soft);
}
.score-breakdown {
margin-top: 10px;
padding: 10px 12px;
border: 1px solid var(--rail-ink);
border-radius: 8px;
background: var(--surface, #fff);
font-size: 0.82rem;
}
.score-breakdown h4 {
display: flex;
justify-content: space-between;
margin: 0 0 6px;
font-size: 0.82rem;
color: var(--ink-soft);
}
.score-breakdown ul {
margin: 0;
padding: 0;
list-style: none;
}
.score-breakdown li {
display: flex;
align-items: baseline;
gap: 8px;
padding: 3px 0;
border-top: 1px solid var(--rail-ink-strong);
}
.score-breakdown li span:first-child {
flex: 1 1 auto;
}
.score-breakdown-excluded strong {
color: var(--green);
}
.score-breakdown-scope {
margin: 0 0 8px;
color: var(--ink-soft);
font-size: 12px;
}
.score-breakdown-clamped {
margin: 8px 0 0;
color: var(--amber);
}
.evidence-group-actions {
display: flex;
align-items: center;
gap: 8px;
}
.duplicate-badge {
display: inline-block;
margin-top: 3px;
padding: 2px 8px;
font-size: 0.7rem;
font-weight: 600;
letter-spacing: 0.01em;
color: var(--blue);
background: var(--blue-tint);
border: 1px solid var(--blue-line);
border-radius: var(--r-pill);
cursor: pointer;
}
.duplicate-badge:hover {
filter: brightness(0.97);
}
.duplicate-badge.conflicting {
color: var(--red);
background: var(--red-tint);
border-color: var(--red-line);
}
/* --- LLM draft (grounded summary + pull into memo) -------------------- */
.llm-draft {
margin: 8px 0;
padding: 10px 12px;
background: var(--violet-tint);
border: 1px solid var(--violet-line);
border-radius: var(--radius);
}
.llm-draft[hidden] { display: none; }
.llm-draft-head {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 4px;
}
.llm-draft-tag {
font-size: 0.7rem;
font-weight: 700;
letter-spacing: 0.02em;
color: var(--violet);
text-transform: uppercase;
}
.llm-draft-body {
margin: 0 0 8px;
font-size: 0.84rem;
line-height: 1.6;
color: var(--ink);
white-space: pre-wrap;
}
.llm-draft-use {
padding: 4px 10px;
font-size: 0.75rem;
color: var(--violet);
background: var(--card);
border: 1px solid var(--violet-line);
border-radius: var(--r-pill);
cursor: pointer;
}
/* --- Stats / calibration view ---------------------------------------- */
.section-sub {
margin: 4px 0 0;
font-size: 0.82rem;
color: var(--ink-soft);
}
.stats-body { display: flex; flex-direction: column; gap: 18px; }
.stat-tiles {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 12px;
}
.stat-tile {
display: flex;
flex-direction: column;
gap: 3px;
padding: 14px 16px;
background: var(--card-raised);
border: 1px solid var(--hair);
border-left: 3px solid var(--hair-strong);
border-radius: var(--radius);
box-shadow: var(--shadow-sm);
}
.stat-tile-label { font-size: 0.76rem; font-weight: 600; color: var(--ink-soft); }
.stat-tile-value { font-size: 1.7rem; font-weight: 700; color: var(--ink); font-variant-numeric: tabular-nums; letter-spacing: -0.02em; }
.stat-tile-sub { font-size: 0.72rem; color: var(--ink-faint); }
.stat-tile.tone-good { border-left-color: var(--green); }
.stat-tile.tone-good .stat-tile-value { color: var(--green); }
.stat-tile.tone-warn { border-left-color: var(--amber); }
.stat-tile.tone-warn .stat-tile-value { color: var(--amber); }
.stat-tile.tone-bad { border-left-color: var(--red); }
.stat-tile.tone-bad .stat-tile-value { color: var(--red); }
.stat-tile.tone-neutral { border-left-color: var(--slate-line); }
.stats-columns {
display: grid;
grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
gap: 16px;
}
@media (max-width: 900px) {
.stats-columns { grid-template-columns: 1fr; }
}
.stats-card {
padding: 16px;
background: var(--card);
border: 1px solid var(--hair);
border-radius: var(--r-lg);
}
.stats-card h2 { margin: 0 0 2px; font-size: 0.95rem; color: var(--ink); }
.stats-matrix { width: 100%; border-collapse: collapse; margin-top: 10px; font-size: 0.82rem; }
.stats-matrix th, .stats-matrix td { padding: 7px 10px; text-align: center; border-bottom: 1px solid var(--hair-soft); }
.stats-matrix thead th { color: var(--ink-soft); font-weight: 600; font-size: 0.76rem; }
.stats-matrix th[scope="row"] { text-align: left; }
.matrix-cell { color: var(--ink-faint); font-variant-numeric: tabular-nums; }
.matrix-cell.has-value { color: var(--ink); font-weight: 600; }
.matrix-total { color: var(--ink-soft); font-weight: 700; font-variant-numeric: tabular-nums; }
.throughput-chart {
display: flex;
align-items: flex-end;
gap: 6px;
height: 160px;
margin-top: 12px;
padding-top: 8px;
}
.throughput-bar {
flex: 1 1 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-end;
gap: 2px;
height: 100%;
min-width: 0;
}
.throughput-bar-fill {
width: 100%;
max-width: 22px;
min-height: 2px;
background: var(--teal);
border-radius: 4px 4px 0 0;
}
.throughput-bar-count { font-size: 0.68rem; color: var(--ink-soft); font-variant-numeric: tabular-nums; }
.throughput-bar-day { font-size: 0.62rem; color: var(--ink-faint); white-space: nowrap; }