recon/static/css/recon.css
Matt 70b80cb312 Phase 6b: fix dashboard Untitled/WEB bug for transcripts
Two bugs in the Recently Completed table:

1. Title showed "Untitled" for all transcripts because the dashboard
   read documents.book_title (populated by PDF metadata voting) which
   is NULL for transcripts. Fixed by COALESCE(book_title, filename)
   in the SQL query -- falls back to catalogue.filename which holds
   the real video title.

2. Type showed "WEB" for all transcripts because the type CASE
   expression only had web and pdf branches, with web matching any
   http% path -- and transcript paths are PeerTube watch URLs.
   Fixed by adding a transcript branch keyed on catalogue.source =
   stream.echo6.co, evaluated before the web branch.

Also adds badge-transcript CSS (purple) and JS rendering case.
Applied consistently to both the Recently Completed and Sources
table queries.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-14 23:05:29 +00:00

317 lines
9.5 KiB
CSS

/* RECON Design System
* Knowledge Extraction Pipeline — Dashboard CSS
*/
:root {
--bg-primary: #0a0a0a;
--bg-secondary: #111;
--bg-tertiary: #1a1a1a;
--border: #222;
--border-light: #333;
--text-primary: #c0c0c0;
--text-muted: #888;
--text-dim: #666;
--text-faint: #555;
--green: #00ff41;
--green-dim: #16a34a;
--red: #ff4444;
--red-dim: #dc2626;
--orange: #ffa500;
--blue: #00bfff;
--blue-sky: #0ea5e9;
--blue-dark: #0284c7;
--purple: #7c3aed;
--yellow: #fbbf24;
/* Pipeline colors */
--pipe-queued: #555;
--pipe-extracting: #b45309;
--pipe-extracted: #d97706;
--pipe-enriching: #0284c7;
--pipe-enriched: #0ea5e9;
--pipe-embedding: #7c3aed;
--pipe-complete: #16a34a;
--pipe-failed: #dc2626;
--font-mono: 'Courier New', monospace;
--radius: 3px;
--radius-md: 4px;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: var(--font-mono); background: var(--bg-primary); color: var(--text-primary); }
/* ── Header ── */
.header {
background: var(--bg-secondary);
border-bottom: 1px solid var(--border-light);
padding: 10px 24px;
flex-shrink: 0;
display: flex;
justify-content: space-between;
align-items: center;
}
.header-left {
display: flex;
align-items: baseline;
gap: 12px;
}
.header-subtitle {
font-size: 11px;
color: var(--text-dim);
letter-spacing: 1px;
text-transform: uppercase;
}
.header h1 { color: var(--green); font-size: 18px; font-weight: 700; letter-spacing: 3px; }
.header .stats { font-size: 12px; color: var(--text-dim); }
.header .quick-stats { font-size: 11px; color: var(--text-muted); display: flex; gap: 16px; }
.header .quick-stats span { white-space: nowrap; }
/* Heartbeat indicator */
.heartbeat {
display: inline-block;
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--green);
margin-right: 6px;
vertical-align: middle;
animation: pulse 2s ease-in-out infinite;
}
.heartbeat.dead {
background: var(--red);
animation: none;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.4; }
}
/* ── Navigation ── */
.nav-domain {
background: #0d0d0d;
border-bottom: 1px solid var(--border);
padding: 0 24px;
display: flex;
gap: 0;
flex-shrink: 0;
}
.nav-domain a {
color: var(--text-muted);
text-decoration: none;
font-size: 13px;
text-transform: uppercase;
letter-spacing: 1px;
padding: 10px 16px;
border-bottom: 2px solid transparent;
transition: color 0.15s, border-color 0.15s;
}
.nav-domain a:hover { color: var(--text-primary); }
.nav-domain a.active {
color: var(--green);
border-bottom-color: var(--green);
}
.nav-sub {
background: var(--bg-primary);
border-bottom: 1px solid var(--border);
padding: 6px 24px;
}
.nav-sub a {
color: var(--text-dim);
text-decoration: none;
margin-right: 16px;
font-size: 12px;
transition: color 0.15s;
}
.nav-sub a:hover { color: var(--text-primary); }
.nav-sub a.active { color: var(--green); }
/* ── Content ── */
.content { padding: 24px; max-width: 1400px; margin: 0 auto; }
/* ── Panels ── */
.panel {
background: var(--bg-secondary);
border: 1px solid var(--border);
padding: 24px;
margin-bottom: 24px;
}
/* ── Forms ── */
.search-box {
width: 100%;
padding: 10px 16px;
background: var(--bg-secondary);
border: 1px solid var(--border-light);
color: var(--text-primary);
font-family: inherit;
font-size: 14px;
margin-bottom: 16px;
}
.search-box:focus { outline: none; border-color: var(--green); }
/* ── Tables ── */
table { width: 100%; border-collapse: collapse; font-size: 13px; }
th { background: var(--bg-secondary); color: var(--green); text-align: left; padding: 8px 12px; border-bottom: 1px solid var(--border-light); }
td { padding: 6px 12px; border-bottom: 1px solid var(--bg-tertiary); }
tr:hover { background: var(--bg-secondary); }
/* ── Status badges ── */
.status { padding: 2px 8px; border-radius: var(--radius); font-size: 11px; }
.status-complete { color: var(--green); }
.status-enriched { color: var(--blue); }
.status-extracted { color: var(--orange); }
.status-failed { color: var(--red); }
.status-queued { color: var(--text-muted); }
.status-duplicate { color: var(--text-muted); }
/* ── Stat cards ── */
.stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 16px; margin-bottom: 24px; }
.stat-card { background: var(--bg-secondary); border: 1px solid var(--border); padding: 16px; }
.stat-card .label { color: var(--text-dim); font-size: 11px; text-transform: uppercase; }
.stat-card .value { color: var(--green); font-size: 28px; margin-top: 4px; }
.stat-card .sublabel { color: var(--text-faint); font-size: 10px; margin-top: 2px; }
/* ── Search results ── */
.result { background: var(--bg-secondary); border: 1px solid var(--border); padding: 16px; margin-bottom: 12px; }
.result .title { color: var(--green); font-size: 14px; margin-bottom: 4px; }
.result .meta { color: var(--text-dim); font-size: 11px; margin-bottom: 8px; }
.result .content-text { color: #999; font-size: 12px; line-height: 1.5; }
.result .score { color: var(--orange); font-size: 12px; float: right; }
/* ── Buttons ── */
.btn {
background: var(--bg-tertiary);
border: 1px solid var(--border-light);
color: var(--text-primary);
padding: 6px 14px;
cursor: pointer;
font-family: inherit;
font-size: 12px;
}
.btn:hover { border-color: var(--green); color: var(--green); }
.btn:disabled { opacity: 0.5; cursor: not-allowed; }
.btn.active { border-color: var(--green); color: var(--green); }
.btn-danger { color: var(--red); }
.btn-danger:hover { border-color: var(--red); }
.btn-warn { color: #ff8800; }
.btn-warn:hover { border-color: #ff8800; }
/* ── Tags ── */
.domain-tag {
display: inline-block;
background: var(--bg-tertiary);
border: 1px solid var(--border-light);
padding: 1px 6px;
margin: 1px;
font-size: 10px;
color: var(--text-muted);
}
.badge-web { background: #1e3a5f; color: #60a5fa; padding: 2px 8px; border-radius: var(--radius); font-size: 11px; }
.badge-pdf { background: #2d5a2d; color: #4ade80; padding: 2px 8px; border-radius: var(--radius); font-size: 11px; }
.badge-transcript { background: #3b1f5e; color: #c084fc; padding: 2px 8px; border-radius: var(--radius); font-size: 11px; }
/* ── Trend indicators ── */
.trend { font-size: 11px; margin-left: 6px; }
.trend-up { color: var(--green); }
.trend-down { color: var(--red); }
.trend-flat { color: var(--text-faint); }
/* ── Pipeline bar ── */
.pipeline-bar {
height: 24px;
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: var(--radius-md);
overflow: hidden;
display: flex;
}
.pipeline-bar .segment { height: 100%; transition: width 0.3s ease; }
.pipeline-legend { display: flex; gap: 14px; margin-top: 6px; font-size: 10px; color: var(--text-muted); flex-wrap: wrap; }
.legend-dot {
display: inline-block;
width: 10px; height: 10px;
border-radius: 2px;
margin-right: 4px;
vertical-align: middle;
}
/* ── Service status dots ── */
.svc-dot {
display: inline-block;
width: 10px;
height: 10px;
border-radius: 50%;
margin-right: 6px;
vertical-align: middle;
}
.svc-dot.active { background: var(--green); }
.svc-dot.inactive { background: var(--red); }
.svc-dot.unknown { background: var(--text-faint); }
/* ── Service status row ── */
.svc-row {
display: flex;
gap: 24px;
background: var(--bg-secondary);
border: 1px solid var(--border);
padding: 12px 16px;
margin-bottom: 24px;
font-size: 12px;
}
.svc-row .svc-item { display: flex; align-items: center; }
/* ── Pagination ── */
.pagination {
display: flex;
gap: 4px;
margin-top: 16px;
justify-content: center;
}
.pagination a, .pagination span {
padding: 4px 10px;
border: 1px solid var(--border-light);
color: var(--text-muted);
text-decoration: none;
font-size: 12px;
}
.pagination a:hover { border-color: var(--green); color: var(--green); }
.pagination .current {
border-color: var(--green);
color: var(--green);
background: var(--bg-tertiary);
}
/* ── Misc helpers ── */
.section-title { color: var(--green); margin-bottom: 12px; }
.mt-24 { margin-top: 24px; }
.mb-16 { margin-bottom: 16px; }
.mb-24 { margin-bottom: 24px; }
.text-muted { color: var(--text-muted); }
.text-dim { color: var(--text-dim); }
.text-faint { color: var(--text-faint); }
.text-green { color: var(--green); }
.text-red { color: var(--red); }
.text-orange { color: var(--orange); }
.text-blue { color: var(--blue); }
.text-small { font-size: 12px; }
.text-xs { font-size: 11px; }
.text-xxs { font-size: 10px; }
.mono { font-family: monospace; }
.flex { display: flex; }
.flex-between { display: flex; justify-content: space-between; }
.flex-center { display: flex; align-items: center; }
.gap-8 { gap: 8px; }
.gap-16 { gap: 16px; }
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; }
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
/* ── Collapsible errors panel ── */
.errors-panel { display: none; }
.errors-panel.has-errors { display: block; }
.errors-panel summary { color: var(--red); cursor: pointer; font-size: 13px; margin-bottom: 8px; }
.errors-panel .error-line { color: var(--text-muted); font-size: 11px; padding: 2px 0; border-bottom: 1px solid var(--border); }