POSA_Copyrighter/web/operator-gui/styles.css
changukyu e38dad83c9 fix: 증거 행 레이아웃·호스트 노출·보존 케이스 설명, 프롬프트 스탬프 갱신
1) 긴 호스트가 제목을 세로 한 줄짜리 컬럼으로 만들었다

   .evidence-title 은 flex-wrap 없는 flex 행이고 source-chip·host-chip 둘 다
   축소를 거부한다(flex: 0 0 auto). 그래서 제목에 남는 폭이 수십 px 이 되고
   overflow-wrap: anywhere 가 그걸 한 단어씩 세로로 쪼갰다. 컨테이너에
   flex-wrap, 제목에 min-width: 14ch 를 줘서 제목이 자기 줄로 내려간다.

   실렌더 측정 (같은 DOM 에 수정 전 CSS 런타임 주입, Playwright):
     360px  제목 51x95px (5줄) -> 246x19px (1줄), 행 높이 95 -> 50
     1280px 제목 9x380px (~20줄) -> 205x19px, 행 높이 380 -> 50

   주석은 데스크톱에서는 해결됐다고 적혀 있었지만, 45자 CDN 호스트로는
   1280px 에서도 재현된다 — 폰 전용 문제가 아니었다.

2) 20ch 로 잘린 호스트를 읽을 방법이 없었다

   칩 title 이 "게시 호스트" 고정 문구여서, 20자 접두어가 같은 두 CDN 호스트를
   링크를 열지 않고 구분할 수 없었다 — 모노스페이스를 고른 이유가 그 판별이다.
   툴팁에 실제 호스트를 싣는다.

3) 클라이언트 호스트 폴백이 서버보다 짧았다

   _result_host 는 (url, result_url, page_url, source_page_url, blogger_link,
   image_url) 를 순회하는데 evidenceHost 는 3개만 봤다. host 키가 생기기 전에
   저장된 네이버 블로그 행이 bloggerLink 만 가진 경우 칩이 조용히 사라졌다 —
   "레거시 증거가 자기 출처에 눈멀지 않게" 라는 폴백의 목적과 반대다.

4) 보존된 케이스가 설명 없는 깨진 이미지였다

   assetMissing 을 읽는 소비자가 GUI·API·내보내기 어디에도 없었다. 판정은 DB 에
   남지만 콘솔에서는 "판정 후 파일 아카이브" 와 "업로드 손상" 이 구분되지
   않았다. 큐 썸네일과 케이스 이미지에 표시 + 파생물 노트에 사유를 붙인다.

5) PROMPT_VERSION 갱신 (ko-v3-structured -> ko-v4-structured-host)

   847f7a8 이 PROMPT_DATA_FIELDS 의 domain -> host 로 모든 증거 줄의 내용을
   바꿨는데 스탬프는 그대로여서, 한 버전이 서로 다른 두 프롬프트를 가리켰다.
   화이트리스트가 다른 모듈에 있어도 프롬프트의 일부라는 점을 llm_prompts
   독스트링의 규칙에 명시했다. 렌더된 줄이 host= 를 담는지 보는 행위 테스트도
   추가했다(튜플 멤버십 검사로는 안 잡힌다).

   CLAUDE.md 요구대로 실모델 프로브(qwen2.5:7b, 로컬 ollama): grounded 3 /
   dropped 0 / verified True, 형식 예시 반향 없음, 인용 라벨 정확(E1=full match).
   다만 모델은 host 를 문장에 쓰지 않고 page_title 로 서술했다 — 호스트는
   운영자 칩에는 닿지만 서술에는 아직 반영되지 않는다(SYSTEM_PROMPT 과제).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BStHFrjQj2VypecSG9ex1V
2026-09-18 23:54:00 +09:00

3197 lines
62 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;
}
/* ===================== 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;
letter-spacing: -0.01em;
}
.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 -------------------------------------------- */
.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; }