Claude-Code 동급 chat 경험으로 끌어올림 + 7개 핵심 흐름 실제 OpenRouter verify.
A — Live verification (scripts/live_verify.py, 7 PASS, 약 $0.02):
- A1 1-turn chat (CLI-eq) → Haiku 4.5 한국어 응답
- A2 sessions resume → 같은 session_id 재투입 시 LangGraph state 복원
- A3 /skill <name> system inject → SKILL.md ("한국어 haiku 3 lines") 가 정확히
3행 한국어 시 생성 (LLM 행동 제어 강력한 증거)
- A4 /plan → /approve → LLM plan markdown only, 차단 도구 시도 없음
- A5 /agents spawn → 실제 sub-agent ainvoke + parent stream push
- A6 auto-compaction → 14 메시지 → 4 archive + 77 토큰 summary
- A7 /workflow wiring → role↔persona 매칭 사전 검증
B1 — Markdown rendering:
- app.js pure-JS 미니 파서: 코드 펜스 / ATX 헤더 / ul/ol / `code`/**bold**/
*italic*/[link](url)
- XSS 정책 유지: createElement + textContent only. 링크 href 는 http(s):
스킴 강제.
B2 — System event card (collapsible):
- _classifySystemMessage 가 [sub-agent .../workflow .../Earlier conversation
history/당신은 plan mode/The user APPROVED/skill] 접두사 분류 후 <details>
카드로 렌더.
B3 — Token streaming via AsyncCallbackHandler:
- ChatOpenAI(streaming=True)
- _StreamingChunkPusher (AsyncCallbackHandler) → asyncio.Queue per session.
- SSE _session_event_stream 이 queue drain → event: chunk SSE. 100ms poll.
- 순서 보장: chunk drain → message rows yield (placeholder 가 메시지로
교체되기 전에 토큰 visible).
- 라이브: 5 chunk events + 1 final message, "안녕하세요, / 무 / 엇을 도와드 /
릴까요?" 토큰 단위 push.
B4 — Cancel mid-turn:
- POST /api/sessions/{id}/abort + app.state.pending_per_session 인덱스.
- 새 user 메시지 도착 시 이전 in-flight task 자동 cancel.
- "■ 중단" 버튼 — 대기 중 visible, 완료/취소 시 hide.
B5 — IME composition-safe Enter:
- compositionstart/compositionend 플래그 — 한글 IME 후보 commit Enter 무시.
- Cmd/Ctrl+Enter 는 항상 전송.
DB hot-fix:
- Database.__init__ pool_pre_ping=True — Postgres asyncpg stale connection
→ SSE 부하에서 500 발생 해결.
기타:
- createNewSession 의 repo_path: "" → "." (min_length=1 검증 통과).
- test_conversation_gui.py fake_invoke 가 chunk_queue kwarg 받도록 업데이트.
게이트:
- ruff / format / mypy: PASS (143 source files)
- pytest -q --ignore=tests/integration/test_e2e_workflow.py
--ignore=tests/integration/test_openrouter_smoke.py: 709 passed
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1214 lines
23 KiB
CSS
1214 lines
23 KiB
CSS
/* my-deepagent Web GUI — v0.2 PR #3 (Claude design pass).
|
||
*
|
||
* Visual reference: Anthropic / Claude design language
|
||
* - Warm cream paper background (#F5F0E8 family)
|
||
* - Charcoal warm-tinted ink for body
|
||
* - Tiempos / Source Serif headings (serif heads, sans body)
|
||
* - Rust / terracotta accent (#CC5500 family)
|
||
* - Generous whitespace, soft 1px borders, minimal shadow
|
||
* - Rounded corners 6–12 px, no heavy elevation
|
||
*
|
||
* Vanilla CSS only. No framework, no build system.
|
||
*/
|
||
|
||
/* ---------- Reset + tokens ---------- */
|
||
|
||
*,
|
||
*::before,
|
||
*::after {
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
:root {
|
||
/* Paper / surface */
|
||
--bg: #f5f0e8;
|
||
--surface-1: #fbfaf6;
|
||
--surface-2: #efe9de;
|
||
--surface-3: #e7e0d3;
|
||
--surface-hover: #eee7da;
|
||
|
||
/* Borders */
|
||
--border: #e2dccf;
|
||
--border-strong: #cfc7b6;
|
||
|
||
/* Ink */
|
||
--text-primary: #1b1916;
|
||
--text-secondary: #54514a;
|
||
--text-muted: #8a857a;
|
||
--text-faint: #b6b0a3;
|
||
|
||
/* Accents (rust + supporting palette) */
|
||
--accent: #c14a1a;
|
||
--accent-hover: #a73d12;
|
||
--accent-bg: rgba(193, 74, 26, 0.1);
|
||
|
||
--success: #4a6f2a;
|
||
--success-bg: rgba(74, 111, 42, 0.1);
|
||
--warning: #a86c1f;
|
||
--warning-bg: rgba(168, 108, 31, 0.12);
|
||
--danger: #a33419;
|
||
--danger-bg: rgba(163, 52, 25, 0.1);
|
||
--info: #4a5d8c;
|
||
--info-bg: rgba(74, 93, 140, 0.1);
|
||
|
||
/* Type */
|
||
--font-serif: "Tiempos Headline", "Source Serif Pro", "IBM Plex Serif",
|
||
"Georgia", "Apple SD Gothic Neo", "Noto Serif KR", serif;
|
||
--font-sans: "Styrene B", "Styrene A", "Inter", "Pretendard",
|
||
-apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo",
|
||
"Noto Sans KR", "Segoe UI", Helvetica, Arial, sans-serif;
|
||
--font-mono: "JetBrains Mono", "SF Mono", "Menlo", "Monaco", "Consolas",
|
||
monospace;
|
||
|
||
/* Geometry */
|
||
--radius-sm: 6px;
|
||
--radius: 8px;
|
||
--radius-lg: 12px;
|
||
|
||
--shadow-card: 0 1px 0 rgba(28, 25, 22, 0.04);
|
||
}
|
||
|
||
/* ---------- Base ---------- */
|
||
|
||
html,
|
||
body {
|
||
margin: 0;
|
||
padding: 0;
|
||
background: var(--bg);
|
||
color: var(--text-primary);
|
||
font-family: var(--font-sans);
|
||
font-size: 15px;
|
||
line-height: 1.55;
|
||
-webkit-font-smoothing: antialiased;
|
||
-moz-osx-font-smoothing: grayscale;
|
||
font-variant-numeric: tabular-nums;
|
||
}
|
||
|
||
body {
|
||
min-height: 100vh;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
a {
|
||
color: var(--accent);
|
||
text-decoration: none;
|
||
transition: color 0.15s ease;
|
||
}
|
||
|
||
a:hover {
|
||
color: var(--accent-hover);
|
||
text-decoration: underline;
|
||
text-decoration-thickness: 1px;
|
||
text-underline-offset: 3px;
|
||
}
|
||
|
||
code,
|
||
kbd,
|
||
.mono {
|
||
font-family: var(--font-mono);
|
||
font-size: 0.86em;
|
||
letter-spacing: -0.005em;
|
||
}
|
||
|
||
::selection {
|
||
background: var(--accent);
|
||
color: var(--surface-1);
|
||
}
|
||
|
||
/* ---------- Header / nav ---------- */
|
||
|
||
header {
|
||
background: transparent;
|
||
border-bottom: 1px solid var(--border);
|
||
padding: 20px 36px;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: baseline;
|
||
gap: 24px;
|
||
}
|
||
|
||
header h1 {
|
||
margin: 0;
|
||
font-family: var(--font-serif);
|
||
font-size: 22px;
|
||
font-weight: 500;
|
||
letter-spacing: -0.02em;
|
||
color: var(--text-primary);
|
||
}
|
||
|
||
header h1 a {
|
||
color: inherit;
|
||
}
|
||
|
||
header h1 a:hover {
|
||
text-decoration: none;
|
||
color: var(--accent);
|
||
}
|
||
|
||
header nav {
|
||
display: flex;
|
||
gap: 4px;
|
||
align-self: center;
|
||
}
|
||
|
||
header nav a {
|
||
color: var(--text-secondary);
|
||
padding: 6px 12px;
|
||
border-radius: var(--radius-sm);
|
||
font-size: 14px;
|
||
font-weight: 400;
|
||
transition: all 0.15s ease;
|
||
}
|
||
|
||
header nav a:hover {
|
||
color: var(--text-primary);
|
||
background: var(--surface-2);
|
||
text-decoration: none;
|
||
}
|
||
|
||
header nav a.active {
|
||
color: var(--accent);
|
||
background: var(--accent-bg);
|
||
}
|
||
|
||
/* ---------- Main ---------- */
|
||
|
||
main {
|
||
flex: 1;
|
||
max-width: 1180px;
|
||
width: 100%;
|
||
margin: 0 auto;
|
||
padding: 40px 36px 64px;
|
||
}
|
||
|
||
.page-title {
|
||
display: flex;
|
||
align-items: baseline;
|
||
justify-content: space-between;
|
||
gap: 16px;
|
||
margin-bottom: 28px;
|
||
border-bottom: 1px solid var(--border);
|
||
padding-bottom: 16px;
|
||
}
|
||
|
||
.page-title h2 {
|
||
margin: 0;
|
||
font-family: var(--font-serif);
|
||
font-size: 30px;
|
||
font-weight: 500;
|
||
letter-spacing: -0.02em;
|
||
text-transform: none;
|
||
color: var(--text-primary);
|
||
}
|
||
|
||
.page-subtitle {
|
||
color: var(--text-muted);
|
||
font-size: 14px;
|
||
}
|
||
|
||
h2 {
|
||
margin: 36px 0 14px;
|
||
font-family: var(--font-serif);
|
||
font-size: 18px;
|
||
font-weight: 500;
|
||
letter-spacing: -0.01em;
|
||
color: var(--text-primary);
|
||
text-transform: none;
|
||
}
|
||
|
||
h2.section-title {
|
||
display: flex;
|
||
align-items: baseline;
|
||
gap: 10px;
|
||
}
|
||
|
||
h2.section-title .hint {
|
||
font-family: var(--font-sans);
|
||
font-size: 13px;
|
||
color: var(--text-muted);
|
||
font-weight: 400;
|
||
margin-left: 4px;
|
||
}
|
||
|
||
/* ---------- Cards / tables ---------- */
|
||
|
||
.card {
|
||
background: var(--surface-1);
|
||
border: 1px solid var(--border);
|
||
border-radius: var(--radius);
|
||
box-shadow: var(--shadow-card);
|
||
overflow: hidden;
|
||
}
|
||
|
||
table {
|
||
width: 100%;
|
||
border-collapse: separate;
|
||
border-spacing: 0;
|
||
font-size: 14px;
|
||
}
|
||
|
||
th,
|
||
td {
|
||
text-align: left;
|
||
padding: 14px 18px;
|
||
border-bottom: 1px solid var(--border);
|
||
vertical-align: middle;
|
||
}
|
||
|
||
tbody tr:last-child td {
|
||
border-bottom: none;
|
||
}
|
||
|
||
tbody tr {
|
||
transition: background 0.12s ease;
|
||
}
|
||
|
||
tbody tr:hover {
|
||
background: var(--surface-2);
|
||
}
|
||
|
||
th {
|
||
background: var(--surface-2);
|
||
color: var(--text-secondary);
|
||
font-weight: 500;
|
||
font-size: 12px;
|
||
letter-spacing: 0.03em;
|
||
text-transform: uppercase;
|
||
padding-top: 11px;
|
||
padding-bottom: 11px;
|
||
border-bottom: 1px solid var(--border-strong);
|
||
}
|
||
|
||
td .mono {
|
||
color: var(--text-secondary);
|
||
}
|
||
|
||
td a {
|
||
font-weight: 500;
|
||
}
|
||
|
||
/* ---------- State badges (pill) ---------- */
|
||
|
||
.badge {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
padding: 3px 11px;
|
||
border-radius: 999px;
|
||
font-size: 12px;
|
||
font-weight: 500;
|
||
letter-spacing: 0.01em;
|
||
border: 1px solid transparent;
|
||
font-variant-numeric: tabular-nums;
|
||
}
|
||
|
||
.badge::before {
|
||
content: "";
|
||
width: 6px;
|
||
height: 6px;
|
||
border-radius: 50%;
|
||
background: currentColor;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.badge.state-completed,
|
||
.badge.state-ok {
|
||
color: var(--success);
|
||
background: var(--success-bg);
|
||
border-color: rgba(74, 111, 42, 0.2);
|
||
}
|
||
|
||
.badge.state-running,
|
||
.badge.state-executing,
|
||
.badge.state-validating,
|
||
.badge.state-awaiting_artifact,
|
||
.badge.state-awaiting_approval {
|
||
color: var(--warning);
|
||
background: var(--warning-bg);
|
||
border-color: rgba(168, 108, 31, 0.22);
|
||
}
|
||
|
||
.badge.state-failed,
|
||
.badge.state-aborted {
|
||
color: var(--danger);
|
||
background: var(--danger-bg);
|
||
border-color: rgba(163, 52, 25, 0.2);
|
||
}
|
||
|
||
.badge.state-pending,
|
||
.badge.state-created,
|
||
.badge.state-bound,
|
||
.badge.state-planning,
|
||
.badge.state-paused,
|
||
.badge.state-skipped {
|
||
color: var(--info);
|
||
background: var(--info-bg);
|
||
border-color: rgba(74, 93, 140, 0.2);
|
||
}
|
||
|
||
.badge.state-running::before,
|
||
.badge.state-executing::before,
|
||
.badge.state-validating::before,
|
||
.badge.state-awaiting_artifact::before {
|
||
animation: pulse 1.6s ease-in-out infinite;
|
||
}
|
||
|
||
@keyframes pulse {
|
||
0%, 100% { opacity: 1; transform: scale(1); }
|
||
50% { opacity: 0.45; transform: scale(0.85); }
|
||
}
|
||
|
||
/* ---------- Buttons ---------- */
|
||
|
||
button,
|
||
.button {
|
||
appearance: none;
|
||
background: var(--surface-1);
|
||
color: var(--text-primary);
|
||
border: 1px solid var(--border-strong);
|
||
border-radius: var(--radius-sm);
|
||
padding: 8px 16px;
|
||
font-family: inherit;
|
||
font-size: 13.5px;
|
||
font-weight: 500;
|
||
letter-spacing: -0.005em;
|
||
cursor: pointer;
|
||
transition: all 0.15s ease;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
text-decoration: none;
|
||
}
|
||
|
||
button:hover:not(:disabled),
|
||
.button:hover {
|
||
background: var(--surface-hover);
|
||
border-color: var(--text-faint);
|
||
color: var(--text-primary);
|
||
text-decoration: none;
|
||
}
|
||
|
||
button:active:not(:disabled) {
|
||
transform: translateY(0.5px);
|
||
}
|
||
|
||
button:disabled {
|
||
opacity: 0.4;
|
||
cursor: not-allowed;
|
||
}
|
||
|
||
button.primary {
|
||
background: var(--accent);
|
||
border-color: var(--accent);
|
||
color: var(--surface-1);
|
||
font-weight: 500;
|
||
}
|
||
|
||
button.primary:hover:not(:disabled) {
|
||
background: var(--accent-hover);
|
||
border-color: var(--accent-hover);
|
||
color: var(--surface-1);
|
||
}
|
||
|
||
button.danger {
|
||
background: transparent;
|
||
color: var(--danger);
|
||
border-color: rgba(163, 52, 25, 0.32);
|
||
}
|
||
|
||
button.danger:hover:not(:disabled) {
|
||
background: var(--danger-bg);
|
||
border-color: var(--danger);
|
||
}
|
||
|
||
/* ---------- Forms ---------- */
|
||
|
||
label {
|
||
display: block;
|
||
margin: 0 0 6px;
|
||
color: var(--text-secondary);
|
||
font-size: 13px;
|
||
font-weight: 500;
|
||
}
|
||
|
||
label .hint {
|
||
color: var(--text-muted);
|
||
font-weight: 400;
|
||
margin-left: 6px;
|
||
font-size: 12.5px;
|
||
}
|
||
|
||
input[type="text"],
|
||
input[type="number"],
|
||
textarea,
|
||
select {
|
||
width: 100%;
|
||
background: var(--surface-1);
|
||
color: var(--text-primary);
|
||
border: 1px solid var(--border);
|
||
border-radius: var(--radius-sm);
|
||
padding: 10px 13px;
|
||
font-family: inherit;
|
||
font-size: 14px;
|
||
line-height: 1.5;
|
||
transition: border-color 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
|
||
}
|
||
|
||
input:focus,
|
||
textarea:focus,
|
||
select:focus {
|
||
outline: none;
|
||
border-color: var(--accent);
|
||
box-shadow: 0 0 0 3px var(--accent-bg);
|
||
}
|
||
|
||
input::placeholder,
|
||
textarea::placeholder {
|
||
color: var(--text-faint);
|
||
}
|
||
|
||
textarea {
|
||
resize: vertical;
|
||
min-height: 110px;
|
||
font-family: var(--font-mono);
|
||
font-size: 13px;
|
||
line-height: 1.6;
|
||
}
|
||
|
||
select {
|
||
appearance: none;
|
||
background-image: url("data:image/svg+xml,%3Csvg width='10' height='6' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%2354514a' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
|
||
background-repeat: no-repeat;
|
||
background-position: right 14px center;
|
||
padding-right: 36px;
|
||
}
|
||
|
||
.form-row {
|
||
margin-bottom: 18px;
|
||
}
|
||
|
||
.form-grid {
|
||
display: grid;
|
||
grid-template-columns: 1fr 220px;
|
||
gap: 16px;
|
||
}
|
||
|
||
.action-bar {
|
||
display: flex;
|
||
gap: 8px;
|
||
margin: 28px 0 0;
|
||
padding-top: 18px;
|
||
border-top: 1px solid var(--border);
|
||
}
|
||
|
||
.action-bar.no-top-border {
|
||
border-top: none;
|
||
padding-top: 0;
|
||
}
|
||
|
||
/* ---------- Meta panel (key/value lists) ---------- */
|
||
|
||
.meta-panel {
|
||
background: var(--surface-1);
|
||
border: 1px solid var(--border);
|
||
border-radius: var(--radius);
|
||
padding: 4px 0;
|
||
box-shadow: var(--shadow-card);
|
||
}
|
||
|
||
.meta-row {
|
||
display: grid;
|
||
grid-template-columns: 150px 1fr;
|
||
gap: 18px;
|
||
padding: 12px 18px;
|
||
border-bottom: 1px solid var(--border);
|
||
align-items: center;
|
||
}
|
||
|
||
.meta-row:last-child {
|
||
border-bottom: none;
|
||
}
|
||
|
||
.meta-row .key {
|
||
color: var(--text-muted);
|
||
font-size: 12.5px;
|
||
font-weight: 500;
|
||
letter-spacing: 0.02em;
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
.meta-row .value {
|
||
color: var(--text-primary);
|
||
font-size: 14px;
|
||
word-break: break-all;
|
||
}
|
||
|
||
.meta-row .value.mono {
|
||
font-family: var(--font-mono);
|
||
font-size: 12.5px;
|
||
color: var(--text-secondary);
|
||
}
|
||
|
||
.meta-row .value.dim {
|
||
color: var(--text-muted);
|
||
}
|
||
|
||
/* ---------- Budget summary cards ---------- */
|
||
|
||
.budget-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||
gap: 14px;
|
||
}
|
||
|
||
.budget-card {
|
||
background: var(--surface-1);
|
||
border: 1px solid var(--border);
|
||
border-radius: var(--radius);
|
||
padding: 18px;
|
||
box-shadow: var(--shadow-card);
|
||
}
|
||
|
||
.budget-card .scope {
|
||
color: var(--text-muted);
|
||
font-size: 12px;
|
||
font-weight: 500;
|
||
letter-spacing: 0.04em;
|
||
text-transform: uppercase;
|
||
margin-bottom: 8px;
|
||
display: -webkit-box;
|
||
-webkit-line-clamp: 1;
|
||
-webkit-box-orient: vertical;
|
||
overflow: hidden;
|
||
white-space: nowrap;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
.budget-card .amount {
|
||
font-family: var(--font-serif);
|
||
font-size: 26px;
|
||
font-weight: 500;
|
||
letter-spacing: -0.02em;
|
||
color: var(--text-primary);
|
||
}
|
||
|
||
.budget-card .amount.warn { color: var(--warning); }
|
||
.budget-card .amount.over { color: var(--danger); }
|
||
|
||
.budget-card .cap {
|
||
font-family: var(--font-sans);
|
||
color: var(--text-muted);
|
||
font-size: 13px;
|
||
font-weight: 400;
|
||
margin-left: 6px;
|
||
}
|
||
|
||
.budget-card .bar {
|
||
height: 4px;
|
||
background: var(--surface-3);
|
||
border-radius: 2px;
|
||
margin-top: 12px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.budget-card .bar > div {
|
||
height: 100%;
|
||
background: var(--success);
|
||
transition: width 0.3s ease;
|
||
}
|
||
|
||
.budget-card .bar.warn > div { background: var(--warning); }
|
||
.budget-card .bar.over > div { background: var(--danger); }
|
||
|
||
/* ---------- Event log (SSE) ---------- */
|
||
|
||
.events {
|
||
background: var(--surface-1);
|
||
border: 1px solid var(--border);
|
||
border-radius: var(--radius);
|
||
max-height: 60vh;
|
||
overflow-y: auto;
|
||
padding: 8px 0;
|
||
font-family: var(--font-mono);
|
||
font-size: 12.5px;
|
||
box-shadow: var(--shadow-card);
|
||
}
|
||
|
||
.event-line {
|
||
display: grid;
|
||
grid-template-columns: 80px 1fr;
|
||
gap: 14px;
|
||
padding: 6px 18px;
|
||
border-bottom: 1px solid transparent;
|
||
}
|
||
|
||
.event-line:hover {
|
||
background: var(--surface-2);
|
||
}
|
||
|
||
.event-line .ts {
|
||
color: var(--text-faint);
|
||
font-size: 11.5px;
|
||
}
|
||
|
||
.event-line .body .type {
|
||
color: var(--accent);
|
||
font-weight: 500;
|
||
}
|
||
|
||
.event-line .body .payload {
|
||
color: var(--text-muted);
|
||
margin-left: 8px;
|
||
font-size: 11.5px;
|
||
word-break: break-all;
|
||
}
|
||
|
||
.event-line.run-completed .body .type { color: var(--success); }
|
||
.event-line.run-failed .body .type,
|
||
.event-line.run-aborted .body .type { color: var(--danger); }
|
||
.event-line.run-resumed .body .type { color: var(--warning); }
|
||
|
||
.events::-webkit-scrollbar {
|
||
width: 10px;
|
||
}
|
||
|
||
.events::-webkit-scrollbar-track {
|
||
background: transparent;
|
||
}
|
||
|
||
.events::-webkit-scrollbar-thumb {
|
||
background: var(--border-strong);
|
||
border-radius: 5px;
|
||
border: 2px solid var(--surface-1);
|
||
}
|
||
|
||
/* ---------- Empty / error states ---------- */
|
||
|
||
.empty {
|
||
padding: 56px 24px;
|
||
text-align: center;
|
||
color: var(--text-muted);
|
||
font-size: 14px;
|
||
}
|
||
|
||
.empty .empty-icon {
|
||
font-family: var(--font-serif);
|
||
font-size: 30px;
|
||
margin-bottom: 10px;
|
||
opacity: 0.5;
|
||
color: var(--accent);
|
||
}
|
||
|
||
.empty .cta {
|
||
margin-top: 18px;
|
||
}
|
||
|
||
.error-banner {
|
||
background: var(--danger-bg);
|
||
border: 1px solid rgba(163, 52, 25, 0.28);
|
||
border-radius: var(--radius);
|
||
padding: 12px 16px;
|
||
margin-bottom: 16px;
|
||
color: var(--danger);
|
||
font-size: 13.5px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
}
|
||
|
||
.error-banner::before {
|
||
content: "!";
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 18px;
|
||
height: 18px;
|
||
background: var(--danger);
|
||
color: var(--surface-1);
|
||
border-radius: 50%;
|
||
font-weight: 700;
|
||
font-size: 11px;
|
||
flex-shrink: 0;
|
||
font-family: var(--font-sans);
|
||
}
|
||
|
||
/* ---------- Tag chip (per-role override input) ---------- */
|
||
|
||
.chips {
|
||
display: grid;
|
||
grid-template-columns: 160px 1fr;
|
||
gap: 14px;
|
||
padding: 14px 18px;
|
||
border-bottom: 1px solid var(--border);
|
||
align-items: center;
|
||
}
|
||
|
||
.chips:last-child {
|
||
border-bottom: none;
|
||
}
|
||
|
||
.chips .role {
|
||
font-size: 13px;
|
||
color: var(--text-secondary);
|
||
font-weight: 500;
|
||
}
|
||
|
||
.chips .role .hint {
|
||
display: block;
|
||
font-size: 12px;
|
||
color: var(--text-muted);
|
||
font-weight: 400;
|
||
margin-top: 2px;
|
||
}
|
||
|
||
.chips input {
|
||
font-family: var(--font-mono);
|
||
font-size: 12.5px;
|
||
}
|
||
|
||
/* ---------- Responsive ---------- */
|
||
|
||
@media (max-width: 720px) {
|
||
main { padding: 24px 16px 40px; }
|
||
header { padding: 16px 16px; }
|
||
.page-title h2 { font-size: 24px; }
|
||
.form-grid { grid-template-columns: 1fr; }
|
||
.meta-row { grid-template-columns: 1fr; gap: 4px; padding: 12px 14px; }
|
||
.event-line { grid-template-columns: 1fr; gap: 2px; }
|
||
.chips { grid-template-columns: 1fr; gap: 6px; }
|
||
}
|
||
|
||
/* =================================================================
|
||
v0.3 PR #8 — Conversation page
|
||
================================================================= */
|
||
|
||
.conversation-main {
|
||
display: flex;
|
||
flex-direction: column;
|
||
min-height: calc(100vh - 80px);
|
||
padding-bottom: 0;
|
||
}
|
||
|
||
.conv-topbar {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
padding: 12px 16px;
|
||
background: var(--bg-card);
|
||
border: 1px solid var(--border);
|
||
border-radius: 8px;
|
||
margin-bottom: 12px;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.conv-label {
|
||
font-size: 13px;
|
||
color: var(--text-muted);
|
||
font-weight: 600;
|
||
}
|
||
|
||
.conv-picker {
|
||
flex: 1;
|
||
min-width: 240px;
|
||
padding: 6px 10px;
|
||
font-family: var(--font-mono);
|
||
font-size: 13px;
|
||
border: 1px solid var(--border);
|
||
border-radius: 6px;
|
||
background: var(--bg);
|
||
}
|
||
|
||
.conv-action-btn {
|
||
padding: 6px 14px;
|
||
font-size: 13px;
|
||
background: var(--accent);
|
||
color: white;
|
||
border: none;
|
||
border-radius: 6px;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.conv-action-btn:hover { filter: brightness(1.08); }
|
||
|
||
.conv-session-state {
|
||
font-size: 11px;
|
||
padding: 2px 8px;
|
||
border-radius: 999px;
|
||
text-transform: lowercase;
|
||
letter-spacing: 0.04em;
|
||
}
|
||
|
||
.conv-session-state.state-active {
|
||
background: rgba(34,197,94,0.12);
|
||
color: rgb(22,163,74);
|
||
}
|
||
|
||
.conv-session-state.state-ended {
|
||
background: rgba(100,116,139,0.12);
|
||
color: rgb(71,85,105);
|
||
}
|
||
|
||
.messages-thread {
|
||
flex: 1;
|
||
overflow-y: auto;
|
||
padding: 16px;
|
||
border: 1px solid var(--border);
|
||
border-radius: 8px;
|
||
background: var(--bg);
|
||
margin-bottom: 12px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 12px;
|
||
}
|
||
|
||
.conv-empty {
|
||
color: var(--text-muted);
|
||
text-align: center;
|
||
padding: 40px 16px;
|
||
font-size: 13px;
|
||
}
|
||
|
||
.msg-bubble {
|
||
max-width: 80%;
|
||
padding: 10px 14px;
|
||
border-radius: 12px;
|
||
font-size: 14px;
|
||
line-height: 1.5;
|
||
white-space: pre-wrap;
|
||
word-break: break-word;
|
||
}
|
||
|
||
.msg-bubble.role-user {
|
||
align-self: flex-end;
|
||
background: var(--accent);
|
||
color: white;
|
||
}
|
||
|
||
.msg-bubble.role-assistant {
|
||
align-self: flex-start;
|
||
background: var(--bg-card);
|
||
border: 1px solid var(--border);
|
||
}
|
||
|
||
.msg-bubble.role-system {
|
||
align-self: center;
|
||
max-width: 90%;
|
||
font-style: italic;
|
||
font-size: 12.5px;
|
||
background: rgba(245,158,11,0.08);
|
||
border: 1px dashed rgba(245,158,11,0.4);
|
||
color: rgb(120,53,15);
|
||
}
|
||
|
||
.msg-bubble.pending {
|
||
opacity: 0.6;
|
||
font-size: 20px;
|
||
padding: 6px 14px;
|
||
}
|
||
|
||
.msg-meta {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
font-size: 11px;
|
||
opacity: 0.6;
|
||
margin-bottom: 4px;
|
||
}
|
||
|
||
.msg-role {
|
||
font-weight: 700;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.05em;
|
||
}
|
||
|
||
.conv-input-bar {
|
||
display: flex;
|
||
gap: 8px;
|
||
padding: 12px;
|
||
background: var(--bg-card);
|
||
border: 1px solid var(--border);
|
||
border-radius: 8px;
|
||
}
|
||
|
||
.conv-input-bar textarea {
|
||
flex: 1;
|
||
font-family: var(--font-body);
|
||
font-size: 14px;
|
||
padding: 8px 10px;
|
||
border: 1px solid var(--border);
|
||
border-radius: 6px;
|
||
resize: vertical;
|
||
min-height: 44px;
|
||
}
|
||
|
||
.conv-input-bar textarea:disabled {
|
||
background: var(--bg);
|
||
opacity: 0.5;
|
||
}
|
||
|
||
.conv-input-bar button {
|
||
padding: 0 18px;
|
||
font-size: 13px;
|
||
background: var(--accent);
|
||
color: white;
|
||
border: none;
|
||
border-radius: 6px;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.conv-input-bar button:disabled {
|
||
opacity: 0.4;
|
||
cursor: not-allowed;
|
||
}
|
||
|
||
|
||
/* =================================================================
|
||
v0.4 — nav tiers + info-box + empty-state polish
|
||
================================================================= */
|
||
|
||
nav .nav-primary {
|
||
font-weight: 600;
|
||
}
|
||
|
||
nav .nav-secondary {
|
||
font-size: 12.5px;
|
||
opacity: 0.65;
|
||
}
|
||
|
||
nav .nav-secondary:hover {
|
||
opacity: 1;
|
||
}
|
||
|
||
nav a.active.nav-primary,
|
||
nav a.active.nav-secondary {
|
||
opacity: 1;
|
||
}
|
||
|
||
.info-box {
|
||
background: rgba(245, 158, 11, 0.08);
|
||
border: 1px solid rgba(245, 158, 11, 0.3);
|
||
border-left: 4px solid rgb(245, 158, 11);
|
||
padding: 14px 18px;
|
||
border-radius: 8px;
|
||
margin-bottom: 20px;
|
||
font-size: 14px;
|
||
line-height: 1.65;
|
||
color: rgb(95, 50, 5);
|
||
}
|
||
|
||
.info-box strong {
|
||
color: rgb(75, 35, 0);
|
||
}
|
||
|
||
.info-box a {
|
||
color: rgb(180, 70, 30);
|
||
text-decoration: underline;
|
||
text-underline-offset: 2px;
|
||
}
|
||
|
||
/* details/summary polish */
|
||
details summary {
|
||
padding: 4px 0;
|
||
}
|
||
|
||
details[open] summary {
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
/* index empty state — prominent CTA */
|
||
.empty-cta {
|
||
text-align: center;
|
||
padding: 64px 20px;
|
||
}
|
||
|
||
.empty-cta-title {
|
||
font-size: 18px;
|
||
font-weight: 600;
|
||
margin-bottom: 8px;
|
||
color: var(--text);
|
||
}
|
||
|
||
.empty-cta-subtitle {
|
||
color: var(--text-muted);
|
||
font-size: 14px;
|
||
margin-bottom: 24px;
|
||
}
|
||
|
||
.empty-cta .button {
|
||
font-size: 15px;
|
||
padding: 12px 24px;
|
||
}
|
||
|
||
/* =================================================================
|
||
v0.4 — workflow generator UI
|
||
================================================================= */
|
||
|
||
.wf-row-card {
|
||
background: var(--bg);
|
||
border: 1px solid var(--border);
|
||
border-radius: 8px;
|
||
padding: 14px 16px;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.wf-row-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 12px;
|
||
padding-bottom: 8px;
|
||
border-bottom: 1px dashed var(--border);
|
||
}
|
||
|
||
.button-link {
|
||
background: none;
|
||
border: none;
|
||
color: rgb(180, 70, 30);
|
||
cursor: pointer;
|
||
font-size: 12px;
|
||
text-decoration: underline;
|
||
padding: 2px 6px;
|
||
}
|
||
|
||
.wf-chip {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
background: rgba(180, 70, 30, 0.06);
|
||
border: 1px solid rgba(180, 70, 30, 0.2);
|
||
border-radius: 999px;
|
||
padding: 3px 10px;
|
||
font-size: 12.5px;
|
||
cursor: pointer;
|
||
margin: 2px 4px 2px 0;
|
||
}
|
||
|
||
.wf-chip input {
|
||
margin: 0;
|
||
}
|
||
|
||
.wf-chip:has(input:checked) {
|
||
background: rgba(180, 70, 30, 0.18);
|
||
border-color: rgba(180, 70, 30, 0.5);
|
||
font-weight: 600;
|
||
}
|
||
|
||
/* =================================================================
|
||
v0.4 — Markdown + system event cards in conversation
|
||
================================================================= */
|
||
|
||
.msg-body .md-p {
|
||
margin: 0 0 8px 0;
|
||
line-height: 1.6;
|
||
}
|
||
|
||
.msg-body .md-p:last-child { margin-bottom: 0; }
|
||
|
||
.msg-body .md-h {
|
||
margin: 12px 0 6px 0;
|
||
font-weight: 700;
|
||
line-height: 1.3;
|
||
}
|
||
|
||
.msg-body .md-ul,
|
||
.msg-body .md-ol {
|
||
margin: 4px 0 8px 0;
|
||
padding-left: 22px;
|
||
line-height: 1.6;
|
||
}
|
||
|
||
.msg-body .md-ul li,
|
||
.msg-body .md-ol li {
|
||
margin: 2px 0;
|
||
}
|
||
|
||
.msg-body .md-code {
|
||
background: rgba(0, 0, 0, 0.04);
|
||
border: 1px solid var(--border);
|
||
border-radius: 6px;
|
||
padding: 10px 12px;
|
||
margin: 8px 0;
|
||
overflow-x: auto;
|
||
font-family: var(--font-mono);
|
||
font-size: 12.5px;
|
||
line-height: 1.45;
|
||
}
|
||
|
||
.msg-body .md-code code {
|
||
background: transparent;
|
||
padding: 0;
|
||
}
|
||
|
||
.msg-body code {
|
||
background: rgba(0, 0, 0, 0.06);
|
||
border-radius: 4px;
|
||
padding: 1px 5px;
|
||
font-family: var(--font-mono);
|
||
font-size: 0.9em;
|
||
}
|
||
|
||
.msg-bubble.role-user .msg-body .md-code,
|
||
.msg-bubble.role-user .msg-body code {
|
||
background: rgba(255, 255, 255, 0.18);
|
||
border-color: rgba(255, 255, 255, 0.3);
|
||
color: white;
|
||
}
|
||
|
||
.msg-body a {
|
||
color: rgb(180, 70, 30);
|
||
text-decoration: underline;
|
||
text-underline-offset: 2px;
|
||
}
|
||
|
||
.msg-bubble.role-user .msg-body a {
|
||
color: white;
|
||
}
|
||
|
||
.msg-body strong { font-weight: 700; }
|
||
.msg-body em { font-style: italic; }
|
||
|
||
/* System event card */
|
||
.msg-bubble.role-system-event {
|
||
align-self: stretch;
|
||
max-width: 100%;
|
||
background: rgba(245, 158, 11, 0.06);
|
||
border: 1px solid rgba(245, 158, 11, 0.25);
|
||
border-style: dashed;
|
||
font-style: normal;
|
||
color: var(--text);
|
||
}
|
||
|
||
.md-system-event summary {
|
||
cursor: pointer;
|
||
font-size: 12.5px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
list-style: none;
|
||
}
|
||
|
||
.md-system-event summary::-webkit-details-marker { display: none; }
|
||
|
||
.md-system-event summary .event-icon {
|
||
font-size: 14px;
|
||
}
|
||
|
||
.md-system-event summary .event-label {
|
||
font-weight: 600;
|
||
letter-spacing: 0.02em;
|
||
color: rgb(120, 53, 15);
|
||
}
|
||
|
||
.md-system-event[open] summary {
|
||
margin-bottom: 8px;
|
||
border-bottom: 1px dashed rgba(245, 158, 11, 0.3);
|
||
padding-bottom: 6px;
|
||
}
|
||
|
||
.md-system-event .event-body {
|
||
font-size: 12.5px;
|
||
line-height: 1.55;
|
||
color: var(--text-muted);
|
||
}
|