POSA_Copyrighter/docs/superpowers/specs/2026-06-11-operator-console-clean-review-ui-design.md
유창욱 ed701bd436 feat: clean review-instrument restyle with bundled Pretendard font
- Bundle Pretendard Variable woff2 locally (air-gapped safe, no CDN)
  and switch UI/stamp font stacks to it; preload in index.html
- Replace the forensic-dossier paper theme with a flat neutral cool
  palette: single teal accent, white cards, no noise texture, and
  zero linear/radial gradients (per design contract)
- Restore the product-purpose top-bar block and its CSS, drop the
  unused global search form, and strip the stray UTF-8 BOM
- Re-skin queue hover/selection, eyebrows, nav rail, chips, and
  empty states to the neutral palette; tabular numerals for numbers
- Regenerate ui-overhaul final audit artifacts: zero horizontal
  overflow across 8 views at 1440x900 and 390x844, Pretendard active

Design spec: docs/superpowers/specs/2026-06-11-operator-console-clean-review-ui-design.md
Plan: docs/plans/2026-06-11-001-feat-operator-console-clean-review-ui-plan.md
Tests: 358 passed (full suite incl. browser smoke)
2026-06-11 10:31:16 +09:00

114 lines
6.2 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Operator Console Clean Review UI — Design Spec
- Date: 2026-06-11
- Status: approved (autonomous goal session)
- Goal: 전체적 UI 점검 및 폰트 변경, 깔끔하게 잘 떨어지는 심사 프로그램의 목적에 맞게 개선
## 1. Problem
The current working-tree restyle ("Forensic Dossier") gives the operator console a
vintage paper-document look: beige paper background with an SVG noise texture,
ochre/teal dual accents, a "stamp" display font (Bahnschrift), and warm hairlines.
That direction conflicts with the product's purpose — a fast, trustworthy,
**clean review instrument** an operator stares at for hours.
Additional defects found during the baseline audit (2026-06-11):
- `tests/operator_gui/test_static_workbench.py::test_workbench_shell_exposes_all_internal_operator_views`
fails: the uncommitted change deleted the `product-purpose` top-bar block and its CSS.
- `index.html` gained a UTF-8 BOM (``).
- Typography relies on Malgun Gothic, which renders Korean UI text loosely and
inconsistently across weights.
- Minor horizontal overflow offenders: `strong` inside desktop queue rows,
`span.provider-chip` on mobile queue (inside the intentionally scrollable table shell).
Baseline artifacts: `data/logs/ui-font-baseline-*.png`, `data/logs/ui-font-baseline-results.json`.
## 2. Approaches Considered
1. **Token re-skin (chosen).** Keep the stylesheet's structure, selectors, and all
test-contract strings; replace the design tokens (`:root`), the body texture,
the font stack, and sweep hardcoded decorative colors. Lowest risk: every
class hook and fixed contract string (queue grid template, audit widths,
floating panel geometry, media queries) survives untouched.
2. Full stylesheet rewrite. Cleanest end state but high risk of dropping one of
the ~30 fixed contract strings the static tests pin; harder to review.
3. Revert to the committed styles and start over. Discards legitimate layout
work already in the working tree (queue grid, floating decision panel).
## 3. Design Decisions
### 3.1 Typography (폰트 변경)
- Bundle **Pretendard Variable** (`web/operator-gui/assets/fonts/PretendardVariable.woff2`,
v1.3.9, 2.06 MB) — downloaded at build time, served locally. **No CDN reference**
at runtime (air-gapped rule).
- `@font-face` with `font-display: swap`, weight range 45920.
- Token changes:
- `--font-ui: "Pretendard Variable", Pretendard, "Malgun Gothic", "Apple SD Gothic Neo", "Segoe UI", system-ui, sans-serif`
- `--font-stamp` (labels, IDs, numeric stamps): same Pretendard stack —
differentiation now comes from weight (650750), size, and `letter-spacing`,
not from a second display face. Bahnschrift is dropped.
- `--font-mono` unchanged (Cascadia Mono / Consolas) for hashes, IDs, code.
- `index.html` gets `<link rel="preload" as="font" type="font/woff2" crossorigin>`
for the woff2.
- Numeric UI (scores, quotas, timestamps) uses `font-variant-numeric: tabular-nums`.
### 3.2 Surface and color (깔끔하게 잘 떨어지는 톤)
- Remove the SVG noise texture and both radial gradient washes from `body`
flat, calm surface.
- Palette shifts from warm paper to neutral cool:
- `--paper` `#f3f5f7` (workspace background), `--paper-2` `#e9edf0`
- `--card` `#ffffff`, `--card-raised` `#ffffff`, `--card-sunk` `#f6f8fa`
- Ink scale: `--ink #1a2128`, `--ink-soft #51606b`, `--ink-faint #8794a1`
- Hairlines: cool grays (`#dde3e8` / `#e7ecf0` / `#b9c4cd`)
- Single primary accent: deep teal-blue (`--teal #1f6f8b` family). The ochre
family stays defined (components reference it) but is re-tuned toward a
restrained amber used only for "hold/attention" semantics, not branding.
- Risk semantics keep their class names and stay high-contrast:
red=high, amber=medium, green=low/approve, plus failed/pending neutrals.
- Shadows get smaller and cooler; radii stay (6/9/14px). No `linear-gradient`
(test contract), and the remaining radial gradients are removed for flatness.
- The dark nav rail stays dark (orientation anchor) but moves to a neutral
slate so the single accent color reads clearly.
### 3.3 Contract restorations
- Re-add the `product-purpose` block to the top bar (`class="product-purpose"`,
`aria-label="제품 목적"`, copy: "이미지 저작권 위험 심사" /
"제출 이미지, 외부 검색 근거, 내부 기준 DB를 한 화면에서 검토합니다.") and its
`.product-purpose` CSS, styled to fit the clean top bar.
- Remove the BOM from `index.html`.
- The deleted global-search form and operator chip stay deleted (no test
references them; the queue has its own search field).
### 3.4 Explicitly preserved test-contract strings in `styles.css`
`grid-template-columns: 28px 64px minmax(104px, 0.68fr) 72px minmax(126px, 0.58fr) minmax(360px, 1.5fr) 82px 76px 90px`,
`--audit-object-width: 24%`, `.audit-table th:nth-child(4)/(5)` with
`width: var(--audit-object-width)`, `.floating-decision-panel` with
`position: fixed` / `bottom: 24px` / `padding-right: 334px` /
`padding-bottom: 260px`, `data-workbench-panel="evidence"` selector,
`@media (max-width: 980px)`, `@media (max-width: 680px)`, `:focus-visible`,
`.risk-high/.risk-medium/.risk-low/.risk-failed`,
`.source-naver/.source-google/.source-llm/.source-internal`,
`.queue-row td:nth-child(5)/(6)`, `white-space: nowrap`, `flex-wrap: nowrap`,
`.queue-provider-strip`, `.coverage-tabs`/`.coverage-tab`, no `linear-gradient`,
no `orb`, obsolete selectors (`.coverage-main`, `.coverage-badges`,
`.coverage-provider-grid`, `.coverage-mini-line`, `.queue-table th:nth-child`)
stay absent.
## 4. Verification Plan (사용자 반응성 검토)
1. `node --check` on touched JS (none expected) and full
`pytest tests/operator_gui` static contracts.
2. Live-server Playwright audit at 1440×900 and 390×844 across all 8 views:
zero horizontal document overflow (`docW <= vw`), regenerate
`data/logs/ui-overhaul-final-results.json` and the 8 contract screenshots.
3. Interaction smoke: existing `test_browser_smoke.py` (suggested-query fill,
real upload flow) must pass against the restyled DOM.
4. Visual review of screenshots: font rendering (Pretendard active), flat
surfaces, risk colors legible, floating decision panel unobstructed.
5. Offline check: grep the GUI for `http://`/`https://` font or CSS fetches —
none allowed.