Files
rfc-app/frontend/src/App.css
T
Ben Stull 4afb018bb0 Contribute rewrite Phase 5: inline word-diff in manual pending card
The §8.11 manual-edit card was a stub — "{N} paragraphs edited
directly" plus a countdown and a Save-now button. The spec says the
card should grow one inline word-diff per touched paragraph as the
contributor types, in the same green/red register the Phase 3 accepted
overlay uses. Phase 5 lands that.

In RFCView.jsx, the 800ms-debounced handleEditorUpdate now computes a
per-paragraph token diff alongside the existing paragraph count and
stores both on manualPending. Baseline is the same Phase 4 gutter
source — originalSourceLinesRef.current, the last server-confirmed
body split on blank lines — so the card resets to empty the same
moment the gutter clears (accept/decline/manualFlush/branch-switch).

In ChangePanel.jsx, diffWords is exported (it was already the AI
card's inline-diff engine — token-level LCS over a whitespace-
preserving /(\\s+)/ split, ~30 lines, no runtime dep). The manual
card consumes the same tokens. Wholly-inserted paragraphs render as
all-insert blocks; wholly-deleted paragraphs as all-delete blocks.

Visual register is intentionally shared with Phase 3's preview
overlay: same #dcfce7/#166534 inserts, same #fee2e2/#991b1b
strike-through deletes. Selectors are scoped under .change-manual-diff
rather than reusing .markdown-preview .tracked-* since the card lives
outside the preview surface.

Pre-fancy stance, matching Phase 4's gutter: the diff is index-aligned
against the baseline, so adding a paragraph in the middle lights up
the rest of the doc. Tolerated as the "you've touched stuff below this
point" cue. An LCS-anchored future pass can fix it.

Verification gap matching Phases 2/3/4: backend was not running this
session, so the live RFCView → real-branch flow wasn't exercised.
Drove the Vite preview sandbox instead — mounted ChangePanel with a
hand-built diffs payload, confirmed three blocks render (mixed edit,
wholly-inserted, wholly-deleted), inserts/deletes carry the expected
computed colors, no console errors. Backend integration suite still
green (125 passed).
2026-05-25 11:29:03 -07:00

1655 lines
56 KiB
CSS

/* App.css — narrowed to slice-1 surfaces. */
.boot {
display: flex; align-items: center; justify-content: center;
height: 100vh; color: #888; font-size: 14px;
}
.app { height: 100vh; display: flex; flex-direction: column; }
.app-header {
height: 48px; flex-shrink: 0;
background: #1a1a1a; color: #fff;
display: flex; align-items: center; justify-content: space-between;
padding: 0 20px;
}
.app-brand a { color: #fff; text-decoration: none; font-weight: 600; font-size: 14px; }
.header-right { display: flex; align-items: center; gap: 12px; font-size: 13px; }
.user-name { color: #ddd; }
.user-role-badge {
font-size: 10px; font-weight: 700;
text-transform: uppercase; letter-spacing: 0.06em;
padding: 2px 6px; border-radius: 4px;
background: rgba(255,255,255,0.15);
}
.role-owner { background: #b45309; }
.role-admin { background: #4338ca; }
.btn-link {
color: #fff; text-decoration: none;
background: rgba(255,255,255,0.15);
border-radius: 6px; padding: 4px 10px;
font-size: 13px;
}
.btn-link:hover { background: rgba(255,255,255,0.25); }
.app-body { flex: 1; display: flex; overflow: hidden; }
/* --- Catalog (left pane, §7) --- */
.catalog {
width: 320px; flex-shrink: 0;
background: #fff; border-right: 1px solid #e5e5e5;
display: flex; flex-direction: column;
overflow: hidden;
}
.catalog-search {
padding: 12px 14px;
border-bottom: 1px solid #f0f0ee;
}
.catalog-search input {
width: 100%; border: 1px solid #e5e5e5; border-radius: 6px;
padding: 6px 10px; font-size: 13px; outline: none;
}
.catalog-search input:focus { border-color: #1a1a1a; }
.catalog-controls {
display: flex; align-items: center; gap: 8px;
padding: 8px 14px;
border-bottom: 1px solid #f0f0ee;
font-size: 12px; color: #555;
}
.catalog-controls select {
border: 1px solid #e5e5e5; border-radius: 4px;
font-size: 12px; padding: 2px 4px;
}
.catalog-chips {
display: flex; flex-wrap: wrap; gap: 4px;
padding: 6px 14px 10px;
border-bottom: 1px solid #f0f0ee;
}
.chip {
font-size: 11px;
background: #f0f0ee; color: #444;
border: 1px solid transparent; border-radius: 999px;
padding: 2px 9px; cursor: pointer;
}
.chip.active { background: #1a1a1a; color: #fff; border-color: #1a1a1a; }
.catalog-list { flex: 1; overflow-y: auto; padding: 4px 0; }
.catalog-row {
display: flex; flex-direction: column;
padding: 8px 14px;
border: none; background: none; text-align: left; cursor: pointer;
border-left: 3px solid transparent; width: 100%;
}
.catalog-row:hover { background: #f7f7f5; }
.catalog-row.active { background: #f0f0ee; border-left-color: #1a1a1a; }
.catalog-row .row-top { display: flex; align-items: center; gap: 6px; }
.row-id {
font-size: 10px; font-weight: 700;
color: #888; text-transform: uppercase;
letter-spacing: 0.04em;
}
.row-id.super { color: #b45309; }
.row-title { font-size: 13px; margin-top: 2px; }
.catalog-row.is-super .row-title { color: #555; }
.row-tags { font-size: 11px; color: #999; margin-top: 2px; }
.catalog-pending {
border-top: 1px solid #f0f0ee;
flex-shrink: 0;
background: #fafaf8;
}
.pending-header {
display: flex; align-items: center; justify-content: space-between;
padding: 8px 14px;
font-size: 11px; font-weight: 700;
text-transform: uppercase; letter-spacing: 0.06em;
color: #888;
cursor: pointer;
background: none; border: none; width: 100%; text-align: left;
}
.pending-count {
background: #e5e5e5; color: #333;
border-radius: 999px;
padding: 1px 8px; font-size: 11px;
}
.pending-list { padding: 2px 0 8px; }
.pending-row {
display: block;
padding: 6px 14px;
font-size: 13px; color: #444; text-decoration: none;
cursor: pointer; background: none; border: none; text-align: left; width: 100%;
}
.pending-row:hover { background: #fff; color: #1a1a1a; }
.pending-row.active { background: #fff; color: #1a1a1a; }
.pending-row .pending-by {
font-size: 11px; color: #999; margin-top: 1px;
}
.catalog-footer {
border-top: 1px solid #e5e5e5;
padding: 10px 14px;
flex-shrink: 0;
background: #fff;
}
.btn-propose {
width: 100%;
background: #1a1a1a; color: #fff;
border: none; border-radius: 6px;
padding: 8px 12px;
font-size: 13px; font-weight: 600;
cursor: pointer;
}
.btn-propose:hover { background: #333; }
.btn-propose:disabled { opacity: 0.5; cursor: default; }
/* --- Main pane --- */
.main-pane {
flex: 1; overflow-y: auto;
padding: 32px 48px;
}
.welcome { max-width: 640px; }
.welcome h1 { font-size: 22px; font-weight: 600; margin: 0 0 16px; }
.welcome p { line-height: 1.7; color: #444; }
/* --- RFC / Proposal view (read-only for slice 1) --- */
.entry-view { max-width: 720px; margin: 0 auto; }
.entry-state-banner {
font-size: 12px; font-weight: 600;
text-transform: uppercase; letter-spacing: 0.06em;
color: #b45309;
padding: 6px 10px;
background: #fffbeb; border: 1px solid #fde68a;
border-radius: 6px;
display: inline-block; margin-bottom: 16px;
}
.entry-state-banner.active { color: #166534; background: #f0fdf4; border-color: #bbf7d0; }
.entry-state-banner.declined { color: #991b1b; background: #fef2f2; border-color: #fecaca; }
.entry-state-banner.merged { color: #1e40af; background: #eff6ff; border-color: #bfdbfe; }
.entry-title { font-size: 26px; font-weight: 700; margin: 0 0 8px; }
.entry-meta { font-size: 12px; color: #999; margin-bottom: 24px; }
.entry-meta .entry-tag {
display: inline-block;
background: #f0f0ee; color: #555;
padding: 1px 8px; border-radius: 999px;
margin-right: 4px;
}
.entry-body {
font-size: 15px; line-height: 1.75; color: #1a1a1a;
}
.entry-body h1, .entry-body h2, .entry-body h3 { font-weight: 600; }
.entry-body h1 { font-size: 22px; margin-top: 24px; }
.entry-body h2 { font-size: 17px; margin-top: 20px; }
.entry-body h3 { font-size: 15px; margin-top: 16px; }
.entry-body p { margin: 0 0 12px; }
.entry-body ul, .entry-body ol { padding-left: 24px; }
.entry-body code { background: #f0f0ee; padding: 1px 5px; border-radius: 3px; font-size: 13px; }
.entry-actions {
display: flex; gap: 8px; margin: 16px 0 24px;
padding-bottom: 24px;
border-bottom: 1px solid #e5e5e5;
}
.btn-primary {
background: #166534; color: #fff;
border: none; border-radius: 6px;
padding: 7px 14px;
font-size: 13px; font-weight: 600;
cursor: pointer;
}
.btn-primary:hover { background: #14532d; }
.btn-primary:disabled { opacity: 0.5; cursor: default; }
.btn-secondary {
background: #fff; color: #1a1a1a;
border: 1px solid #d4d4d4; border-radius: 6px;
padding: 7px 14px;
font-size: 13px; font-weight: 600;
cursor: pointer;
}
.btn-secondary:hover { background: #f7f7f5; }
.btn-danger {
background: #fff; color: #991b1b;
border: 1px solid #fecaca; border-radius: 6px;
padding: 7px 14px;
font-size: 13px; font-weight: 600;
cursor: pointer;
}
.btn-danger:hover { background: #fef2f2; }
/* --- Modals --- */
.modal-overlay {
position: fixed; inset: 0;
background: rgba(20, 20, 20, 0.4);
display: flex; align-items: center; justify-content: center;
z-index: 100;
}
.modal {
background: #fff;
border-radius: 10px;
box-shadow: 0 12px 40px rgba(0,0,0,0.15);
width: 560px; max-width: calc(100vw - 40px);
max-height: calc(100vh - 80px);
display: flex; flex-direction: column;
}
.modal-header {
padding: 18px 20px;
border-bottom: 1px solid #f0f0ee;
display: flex; align-items: center; justify-content: space-between;
}
.modal-header h2 { margin: 0; font-size: 17px; font-weight: 600; }
.modal-close {
background: none; border: none; font-size: 22px; cursor: pointer;
color: #999; line-height: 1; padding: 0;
}
.modal-body {
padding: 20px;
overflow-y: auto;
flex: 1;
}
.modal-body label {
display: block;
font-size: 12px; font-weight: 600;
color: #555;
text-transform: uppercase; letter-spacing: 0.05em;
margin-bottom: 4px;
}
.modal-body input, .modal-body textarea {
width: 100%;
border: 1px solid #d4d4d4; border-radius: 6px;
padding: 8px 10px;
font-size: 14px; font-family: inherit;
outline: none; margin-bottom: 14px;
}
.modal-body input:focus, .modal-body textarea:focus { border-color: #1a1a1a; }
.modal-body textarea { resize: vertical; min-height: 100px; }
.field-help {
font-size: 12px; color: #999;
margin-top: -10px; margin-bottom: 14px;
}
.field-error {
font-size: 12px; color: #991b1b;
margin-top: -10px; margin-bottom: 14px;
}
.modal-actions {
border-top: 1px solid #f0f0ee;
padding: 14px 20px;
display: flex; justify-content: flex-end; gap: 10px;
}
/* --- Landing page (pre-login, §14.1) --- */
.landing {
height: 100vh;
display: flex; flex-direction: column;
align-items: center; justify-content: center;
padding: 40px;
text-align: center;
}
.landing h1 { font-size: 28px; font-weight: 700; margin: 0 0 8px; }
.landing .subtitle { font-size: 16px; color: #666; margin: 0 0 28px; }
.landing .pitch {
max-width: 540px;
line-height: 1.7; color: #333;
font-size: 15px;
margin: 0 0 28px;
}
.landing .btn-signin {
background: #1a1a1a; color: #fff;
border: none; border-radius: 8px;
padding: 10px 20px;
font-size: 14px; font-weight: 600;
text-decoration: none;
}
.landing .btn-signin:hover { background: #333; }
.landing .secondary-link {
margin-top: 14px;
font-size: 13px;
color: #666; text-decoration: none;
}
.landing .secondary-link:hover { color: #1a1a1a; text-decoration: underline; }
/* ── §8 RFC view: three-column shape ─────────────────────────────────── */
.main-pane {
/* Override the §9.x padded read-view; the §8 surface manages its own
internal layout and needs to fill the pane edge-to-edge. */
padding: 0;
overflow: hidden;
display: flex;
}
.rfc-view {
flex: 1; min-width: 0;
display: flex; flex-direction: column;
overflow: hidden;
}
.rfc-breadcrumb {
display: flex; align-items: center; gap: 8px;
padding: 10px 16px;
border-bottom: 1px solid #e5e5e5;
background: #fafafa;
font-size: 13px; color: #555;
flex-shrink: 0;
}
.breadcrumb-label {
font-size: 11px; font-weight: 700; text-transform: uppercase;
letter-spacing: 0.05em; color: #888;
}
.breadcrumb-sep { color: #ccc; }
.breadcrumb-meta { color: #999; font-size: 12px; }
.breadcrumb-actions { margin-left: auto; display: flex; gap: 8px; align-items: center; }
.btn-mode-toggle {
font-size: 12px; font-weight: 600;
padding: 4px 12px; border-radius: 999px;
border: 1px solid #d4d4d4; background: #fff; color: #444;
cursor: pointer;
}
.btn-mode-toggle.discuss { background: #fff; color: #444; }
.btn-mode-toggle.contribute { background: #1a1a1a; color: #fff; border-color: #1a1a1a; }
.btn-start-contribution-header {
background: #1a1a1a; color: #fff;
border: none; border-radius: 6px;
padding: 5px 12px; font-size: 12px; font-weight: 600;
cursor: pointer;
}
.branch-dropdown { position: relative; }
.branch-dropdown-trigger {
background: none; border: 1px solid transparent; border-radius: 5px;
padding: 3px 8px; font-weight: 600; color: #1a1a1a; font-size: 13px;
cursor: pointer;
}
.branch-dropdown-trigger:hover { border-color: #e5e5e5; }
.branch-dropdown-menu {
position: absolute; top: 100%; left: 0; margin-top: 4px;
background: #fff; border: 1px solid #e5e5e5; border-radius: 8px;
box-shadow: 0 4px 20px rgba(0,0,0,0.08);
z-index: 50; min-width: 240px; padding: 4px;
}
.branch-dropdown-item {
display: flex; align-items: center; gap: 8px;
width: 100%; padding: 6px 10px;
background: none; border: none; cursor: pointer; text-align: left;
font-size: 13px; border-radius: 5px;
}
.branch-dropdown-item:hover { background: #f5f5f5; }
.branch-dropdown-item.active { background: #f0f0ee; font-weight: 600; }
.branch-name { flex: 1; }
.branch-creator { font-size: 11px; color: #999; }
.branch-private-icon { font-size: 10px; }
.rfc-body { flex: 1; display: flex; overflow: hidden; }
/* ── Editor area ─────────────────────────────────────────────────────── */
.editor-area {
flex: 1; min-width: 0;
display: flex; flex-direction: column;
overflow: hidden; position: relative;
background: #fff;
}
.discuss-mode-banner {
padding: 8px 16px;
background: #fffbeb; border-bottom: 1px solid #fde68a;
color: #92400e; font-size: 12px;
}
.discuss-mode-banner.muted { background: #f0f0ee; color: #666; border-color: #e5e5e5; }
.editor-toolbar {
display: flex; align-items: center; gap: 12px;
padding: 8px 16px;
border-bottom: 1px solid #f0f0ee;
background: #fafafa;
font-size: 12px; color: #777;
}
.btn-review-toggle {
background: #fff; color: #1a1a1a;
border: 1px solid #d4d4d4; border-radius: 5px;
padding: 4px 10px; font-size: 12px; font-weight: 600; cursor: pointer;
}
.btn-review-toggle.active { background: #1a1a1a; color: #fff; border-color: #1a1a1a; }
.editor-toolbar-hint { color: #999; font-size: 11px; }
.editor-wrapper {
flex: 1; overflow-y: auto;
padding: 32px 48px;
}
.editor-content {
max-width: 720px; margin: 0 auto; outline: none;
}
.editor-content .tiptap {
outline: none; font-size: 15px; line-height: 1.75; color: #1a1a1a;
}
.editor-content .tiptap h1 { font-size: 22px; font-weight: 700; margin: 24px 0 12px; }
.editor-content .tiptap h2 { font-size: 17px; font-weight: 600; margin: 20px 0 8px; }
.editor-content .tiptap h3 { font-size: 15px; font-weight: 600; margin: 16px 0 6px; }
.editor-content .tiptap p { margin: 0 0 12px; }
.editor-content .tiptap ul, .editor-content .tiptap ol { padding-left: 24px; }
.editor-content .tiptap code { background: #f0f0ee; padding: 1px 5px; border-radius: 3px; font-size: 13px; }
.editor-content .tiptap .selection-highlight {
background: rgba(99, 102, 241, 0.15);
border-radius: 2px;
outline: 1px solid rgba(99, 102, 241, 0.3);
outline-offset: 1px;
}
.editor-content .tiptap .tracked-delete {
background: #fee2e2; color: #991b1b; text-decoration: line-through;
border-radius: 2px; padding: 1px 2px; cursor: pointer;
}
.editor-content .tiptap .tracked-insert {
background: #dcfce7; color: #166534;
border-radius: 2px; padding: 1px 2px; cursor: pointer;
}
/* CodeMirror 6 source editor (Contribute mode). */
.cm-source-editor {
flex: 1; min-height: 0;
display: flex; flex-direction: column;
overflow: hidden;
}
/* ── Split-pane Contribute layout (Phase 2) ──────────────────────────── */
.editor-split {
flex: 1; min-height: 0;
display: flex; flex-direction: row;
overflow: hidden;
}
.editor-split-pane {
flex: 1 1 50%; min-width: 0; min-height: 0;
display: flex; flex-direction: column;
overflow: hidden;
}
.editor-split-raw { border-right: 1px solid #e5e5e5; }
.editor-split-preview { background: #fff; overflow-y: auto; }
.editor-split-preview .markdown-preview { padding: 24px 32px; }
/* ── Markdown preview (Phase 2 render pane) ──────────────────────────── */
.markdown-preview {
font-size: 15px; line-height: 1.75; color: #1a1a1a;
max-width: 720px; margin: 0 auto;
outline: none;
}
.markdown-preview-solo {
flex: 1; overflow-y: auto;
padding: 32px 48px;
}
.markdown-preview h1 { font-size: 22px; font-weight: 700; margin: 24px 0 12px; }
.markdown-preview h2 { font-size: 17px; font-weight: 600; margin: 20px 0 8px; }
.markdown-preview h3 { font-size: 15px; font-weight: 600; margin: 16px 0 6px; }
.markdown-preview p { margin: 0 0 12px; }
.markdown-preview ul, .markdown-preview ol { padding-left: 24px; }
.markdown-preview code {
background: #f0f0ee; padding: 1px 5px; border-radius: 3px; font-size: 13px;
}
.markdown-preview pre {
background: #f6f6f4; padding: 12px 16px; border-radius: 6px;
overflow-x: auto; font-size: 13px; line-height: 1.5;
}
.markdown-preview pre code { background: none; padding: 0; }
.markdown-preview blockquote {
margin: 0 0 12px; padding: 4px 14px;
border-left: 3px solid #d4d4d4; color: #555;
}
.markdown-preview table { border-collapse: collapse; margin: 0 0 12px; }
.markdown-preview th, .markdown-preview td {
border: 1px solid #e5e5e5; padding: 6px 10px;
}
.markdown-preview th { background: #fafafa; font-weight: 600; }
/* Mermaid placeholder shown until the lazy-loaded module resolves.
The .mermaid-block container is preserved so future authoring tools
can decorate it; SVG output replaces only the inner contents. */
.markdown-preview .mermaid-block {
margin: 12px 0;
text-align: center;
}
.markdown-preview .mermaid-block svg { max-width: 100%; height: auto; }
.markdown-preview .mermaid-placeholder {
background: #f6f6f4; color: #777;
padding: 12px 16px; border-radius: 6px;
font-size: 12px; line-height: 1.5;
text-align: left; white-space: pre-wrap;
}
.markdown-preview .mermaid-error {
background: #fee2e2; color: #991b1b;
padding: 10px 14px; border-radius: 6px;
font-size: 12px; line-height: 1.5;
text-align: left; white-space: pre-wrap;
}
/* Browser-native selection styling inside the preview — replaces the
PM selection-highlight plugin that lived in Tiptap's surface. The
SelectionTooltip's onMouseDown preventDefault keeps the selection
visible while the tooltip captures input. */
.markdown-preview ::selection {
background: rgba(99, 102, 241, 0.22);
}
/* Tracked-change overlay (Phase 3, §8.10) — preview-pane equivalents of
the .editor-content .tiptap rules above. The Contribute pane shows
these by default; the Discuss pane gates them behind a toolbar
toggle. Hovering surfaces a ChangeTooltip with the source message
and reason. */
.markdown-preview .tracked-delete {
background: #fee2e2; color: #991b1b; text-decoration: line-through;
border-radius: 2px; padding: 1px 2px; cursor: pointer;
margin-right: 2px;
}
.markdown-preview .tracked-insert {
background: #dcfce7; color: #166534;
border-radius: 2px; padding: 1px 2px; cursor: pointer;
}
/* Narrow-viewport banner — Phase 2 punts the chat-drawer collapse to
Phase 6, so the split layout asks for ≥1280px. */
.narrow-viewport-banner {
padding: 8px 16px;
background: #fef3c7; border-bottom: 1px solid #fcd34d;
color: #78350f; font-size: 12px;
}
@media (min-width: 1280px) {
.narrow-viewport-banner { display: none; }
}
.cm-source-editor .cm-editor {
flex: 1; min-height: 0;
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
font-size: 13px; line-height: 1.6;
background: #fff;
}
.cm-source-editor .cm-editor.cm-focused { outline: none; }
.cm-source-editor .cm-scroller { padding: 24px 0; }
.cm-source-editor .cm-content { padding: 0 32px; max-width: 880px; }
.cm-source-editor .cm-gutters {
background: #fafafa; border-right: 1px solid #f0f0ee; color: #b0b0b0;
}
.cm-source-editor .cm-activeLineGutter { background: #f3f4f6; color: #555; }
.cm-source-editor .cm-activeLine { background: #fafbfc; }
/* §8.10 paragraph-margin marker (Phase 4) — gutter accent on lines
that differ from the open-session baseline (last server-confirmed
body). A scannable "did anything change in this region?" cue,
visually distinct from the preview pane's green/red tracked-insert
/ tracked-delete overlay. Amber signals in-flight / uncommitted. */
.cm-source-editor .cm-diff-gutter {
width: 3px; padding: 0;
background: transparent;
}
.cm-source-editor .cm-diff-gutter .cm-gutterElement {
padding: 0;
}
.cm-source-editor .cm-diff-gutter-mark {
width: 3px; height: 100%;
background: #f59e0b;
}
.readonly-bar {
border-top: 1px solid #e5e5e5;
padding: 10px 16px; text-align: center;
font-size: 13px; color: #888; background: #fafafa;
}
.readonly-bar a { color: #1a1a1a; font-weight: 600; }
/* ── Prompt bar ──────────────────────────────────────────────────────── */
.prompt-bar {
border-top: 1px solid #e5e5e5;
background: #fff;
padding: 12px 48px;
flex-shrink: 0;
}
.selection-badge {
font-size: 12px; color: #5b5bd6;
margin-bottom: 8px; display: flex; align-items: center; gap: 6px;
}
.selection-icon { font-size: 10px; }
.prompt-row {
display: flex; gap: 10px; align-items: flex-end;
max-width: 720px; margin: 0 auto;
}
.prompt-input {
flex: 1; border: 1px solid #e5e5e5; border-radius: 8px;
padding: 9px 13px; font-size: 14px; font-family: inherit;
resize: none; line-height: 1.5; outline: none;
min-height: 40px; max-height: 120px;
}
.prompt-input:focus { border-color: #1a1a1a; }
.prompt-submit {
background: #1a1a1a; color: #fff; border: none;
border-radius: 8px; padding: 9px 16px;
font-size: 13px; font-weight: 600; cursor: pointer;
height: 40px;
}
.prompt-submit:disabled { background: #ccc; cursor: default; }
/* ── Model picker ──────────────────────────────────────────────────── */
.model-picker { display: flex; gap: 4px; padding: 0 4px; flex-shrink: 0; }
.model-pill {
display: flex; align-items: center; gap: 5px;
padding: 4px 10px; border-radius: 20px;
font-size: 12px; font-weight: 600;
border: 1px solid #e5e5e5; background: none; color: #666;
cursor: pointer;
}
.model-pill:hover { border-color: #aaa; color: #333; }
.model-pill.active { font-weight: 700; }
.model-dot { width: 7px; height: 7px; border-radius: 50%; }
/* ── Selection tooltip ───────────────────────────────────────────────── */
.selection-tooltip {
position: fixed; z-index: 100;
background: #fff; border: 1px solid #e5e5e5;
border-radius: 10px;
box-shadow: 0 4px 20px rgba(0,0,0,0.12);
padding: 8px 10px;
width: max-content; min-width: 320px; max-width: 480px;
display: flex; flex-direction: column; gap: 6px;
}
.selection-tooltip-quote {
font-size: 11px; color: #888; font-style: italic;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.selection-tooltip-tabs { display: flex; gap: 4px; }
.selection-tooltip-tab {
background: none; border: 1px solid transparent;
font-size: 12px; padding: 3px 10px; border-radius: 6px;
cursor: pointer; color: #666;
}
.selection-tooltip-tab.active { background: #1a1a1a; color: #fff; }
.selection-tooltip-input-row { display: flex; gap: 6px; align-items: center; }
.selection-tooltip-input {
flex: 1; border: 1px solid #e5e5e5; border-radius: 6px;
padding: 6px 10px; font-size: 13px; font-family: inherit; outline: none;
background: #f9f9f9;
}
.selection-tooltip-input:focus { border-color: #1a1a1a; background: #fff; }
.selection-tooltip-btn {
background: #1a1a1a; color: #fff;
border: none; border-radius: 6px;
padding: 6px 12px; font-size: 13px; font-weight: 600; cursor: pointer;
}
.selection-tooltip-btn:disabled { background: #ccc; cursor: default; }
/* ── Right panel (chat + change panel) ───────────────────────────────── */
.right-panel {
width: 360px; flex-shrink: 0;
border-left: 1px solid #e5e5e5;
display: flex; flex-direction: column;
overflow: hidden; background: #fff;
}
.chat-panel {
flex: 1; display: flex; flex-direction: column;
overflow: hidden; min-height: 0;
}
.chat-header {
padding: 10px 14px;
border-bottom: 1px solid #f0f0ee;
background: #fafafa;
display: flex; flex-direction: column; gap: 4px;
}
.chat-header-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.chat-header-title { font-size: 12px; color: #555; }
.chat-fork-link {
background: none; border: none; padding: 0;
font-size: 11px; color: #5b5bd6; cursor: pointer;
}
.chat-thread-disclosure {
font-size: 11px; color: #888;
display: flex; gap: 4px; align-items: center;
}
.chat-thread-flag-count { color: #b45309; }
.chat-filter-clear {
margin-left: auto;
background: none; border: none; cursor: pointer;
font-size: 11px; color: #5b5bd6;
}
.chat-messages {
flex: 1; overflow-y: auto;
padding: 14px;
display: flex; flex-direction: column; gap: 10px;
}
.chat-empty {
flex: 1; display: flex; flex-direction: column;
align-items: center; justify-content: center;
text-align: center; padding: 24px;
}
.chat-empty p { font-size: 13px; color: #999; line-height: 1.6; max-width: 240px; }
.chat-message { display: flex; flex-direction: column; gap: 3px; }
.chat-message.user { align-items: flex-end; }
.chat-message.assistant { align-items: flex-start; }
.chat-message.system { align-items: stretch; }
.chat-message.flag { align-items: stretch; }
.chat-message.in-thread { padding-left: 12px; border-left: 2px solid #c4b5fd; }
.chat-bubble {
max-width: 92%;
padding: 8px 11px; border-radius: 14px;
font-size: 13px; line-height: 1.55;
white-space: pre-wrap; word-break: break-word;
}
.chat-message.user .chat-bubble {
background: #1a1a1a; color: #fff; border-bottom-right-radius: 4px;
}
.chat-message.assistant .chat-bubble {
background: #f3f4f6; color: #1a1a1a; border-bottom-left-radius: 4px;
}
.chat-message.streaming .chat-bubble { opacity: 0.85; }
.chat-thinking { color: #999; font-style: italic; }
.chat-cursor {
display: inline-block; width: 2px; height: 12px;
background: #7c3aed; margin-left: 2px; vertical-align: middle;
animation: blink 0.75s step-end infinite;
}
@keyframes blink { 0%, 100% { opacity: 1; } 50% { opacity: 0; } }
.chat-quote {
font-size: 11px; color: #888; font-style: italic;
border-left: 2px solid #d1d5db; padding-left: 7px; margin-bottom: 3px;
max-width: 92%; align-self: flex-end;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.chat-anchor-preview {
font-size: 10px; color: #888; font-style: italic;
}
.chat-model-label {
font-size: 11px; font-weight: 700;
display: flex; align-items: center; gap: 4px; padding-left: 2px;
}
.chat-model-dot { width: 6px; height: 6px; border-radius: 50%; }
.chat-change-hint {
align-self: flex-start;
background: none; border: none; padding: 0;
font-size: 11px; color: #7c3aed; font-weight: 600;
cursor: pointer;
}
.chat-change-hint.discuss { color: #b45309; }
.chat-change-hint-cta {
background: none; border: none; padding: 0;
color: #5b5bd6; font-weight: 600; cursor: pointer; text-decoration: underline;
}
.chat-system-bubble {
font-size: 11px; color: #888; font-style: italic;
border-top: 1px dashed #e5e5e5; padding-top: 8px;
}
.chat-flag-row {
display: flex; gap: 8px;
padding: 8px 10px;
background: #fff7ed; border: 1px solid #fdba74; border-radius: 8px;
}
.chat-flag-icon { color: #c2410c; font-size: 14px; }
.chat-flag-content { flex: 1; }
.chat-flag-author { font-size: 11px; font-weight: 700; color: #9a3412; }
.chat-flag-text { font-size: 13px; color: #1a1a1a; margin-top: 2px; }
.chat-flag-resolve {
margin-top: 6px;
background: none; border: 1px solid #fdba74;
border-radius: 5px; padding: 2px 8px;
font-size: 11px; color: #c2410c; cursor: pointer;
}
/* ── Change panel ──────────────────────────────────────────────── */
.change-panel {
border-top: 1px solid #e5e5e5;
display: flex; flex-direction: column;
overflow: hidden; flex-shrink: 0;
max-height: 50%;
}
.change-panel-header {
padding: 12px 14px;
font-size: 13px; font-weight: 600;
border-bottom: 1px solid #f0f0ee;
display: flex; align-items: center; gap: 8px;
}
.badge {
background: #b45309; color: #fff;
font-size: 11px; padding: 2px 7px; border-radius: 10px;
}
.change-list { flex: 1; overflow-y: auto; padding: 8px; }
.change-group-label {
font-size: 10px; font-weight: 700;
text-transform: uppercase; letter-spacing: 0.06em;
color: #aaa; padding: 8px 6px 4px;
}
.change-group-label.muted { color: #ccc; }
.change-item {
border-radius: 8px;
padding: 10px;
margin-bottom: 8px;
border: 1px solid #e5e5e5;
font-size: 13px;
}
.change-item.type-claude { border-left: 3px solid #5b5bd6; }
.change-item.type-manual { border-left: 3px solid #888; }
.change-item.state-accepted { opacity: 0.5; }
.change-item.state-declined { opacity: 0.4; }
.change-item.stale { border-color: #fbbf24; background: #fffbeb; }
.change-item.focused {
animation: change-focus-flash 1.8s ease forwards;
}
@keyframes change-focus-flash {
0% { box-shadow: 0 0 0 3px #3b82f6; }
70% { box-shadow: 0 0 0 3px #3b82f6; }
100% { box-shadow: none; }
}
.change-meta {
display: flex; align-items: center; justify-content: space-between;
margin-bottom: 6px;
}
.change-author { font-weight: 600; font-size: 12px; }
.change-state-badge {
font-size: 10px; padding: 2px 7px; border-radius: 10px;
font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em;
}
.change-state-badge.pending { background: #fef3c7; color: #92400e; }
.change-state-badge.accepted { background: #dcfce7; color: #166534; }
.change-state-badge.declined { background: #f1f5f9; color: #94a3b8; }
.change-state-badge.stale { background: #fef3c7; color: #92400e; }
.change-label { color: #444; margin-bottom: 6px; line-height: 1.4; }
.change-stale-banner {
font-size: 11px; color: #92400e;
background: #fef3c7; border-radius: 4px;
padding: 4px 8px; margin-bottom: 6px;
}
.change-manual-status {
font-size: 11px; color: #888;
display: flex; align-items: center; justify-content: space-between;
margin-top: 6px;
}
/* §8.11 Phase 5 — per-paragraph word-diff inside the pending manual
card. Shares Phase 3's green/red register with .markdown-preview
.tracked-insert / .tracked-delete so the contributor sees one
"change layer" vocabulary across the preview pane (accepted) and the
change card (their own pending typing). Scoped under its own class
rather than reusing the preview selectors since the card is not
inside .markdown-preview. */
.change-manual-diff {
margin: 6px 0;
display: flex; flex-direction: column; gap: 6px;
}
.change-manual-diff-block {
font-size: 12px; line-height: 1.6;
background: #f9fafb; border-radius: 4px;
padding: 6px 8px; border: 1px solid #e5e5e5;
white-space: pre-wrap; word-break: break-word;
}
.change-manual-diff .manual-diff-insert {
background: #dcfce7; color: #166534;
border-radius: 2px; padding: 1px 2px;
}
.change-manual-diff .manual-diff-delete {
background: #fee2e2; color: #991b1b;
text-decoration: line-through;
border-radius: 2px; padding: 1px 2px;
}
.btn-save-now {
background: none; border: 1px solid #d4d4d4;
border-radius: 4px; padding: 2px 8px;
font-size: 11px; font-weight: 600; cursor: pointer;
}
.change-source-link {
background: none; border: none; padding: 0;
font-size: 11px; color: #5b5bd6; cursor: pointer;
display: block; margin-top: 4px;
}
.change-actions { display: flex; gap: 6px; margin-top: 8px; flex-wrap: wrap; }
.btn-accept {
background: #166534; color: #fff;
border: none; border-radius: 5px;
padding: 5px 10px; font-size: 12px; font-weight: 600; cursor: pointer;
}
.btn-edit {
background: none; border: 1px solid #c4b5fd; color: #7c3aed;
border-radius: 5px; padding: 5px 10px; font-size: 12px; font-weight: 600; cursor: pointer;
}
.btn-decline {
background: none; border: 1px solid #e5e5e5;
border-radius: 5px; padding: 5px 10px; font-size: 12px; cursor: pointer;
}
.btn-reask {
background: none; border: 1px solid #fbbf24; color: #92400e;
border-radius: 5px; padding: 5px 10px; font-size: 12px; font-weight: 600; cursor: pointer;
}
.diff-edit-textarea {
width: 100%; font-size: 12px; font-family: inherit;
line-height: 1.5; border: 1px solid #c4b5fd;
border-radius: 4px; padding: 6px; resize: vertical;
}
.inline-diff {
font-size: 12px; line-height: 1.7;
background: #f9fafb; border-radius: 4px;
padding: 8px 10px;
white-space: pre-wrap; word-break: break-word;
border: 1px solid #e5e5e5;
}
.diff-word-add {
background: #dcfce7; color: #166534;
border-radius: 2px; padding: 1px 1px;
}
.diff-word-remove {
background: #fee2e2; color: #991b1b;
text-decoration: line-through;
border-radius: 2px; padding: 1px 1px;
}
.text-fade { color: #aaa; }
.expand-toggle {
display: block; margin-top: 5px;
background: none; border: none; padding: 0;
font-size: 11px; font-weight: 600; color: #7c3aed;
cursor: pointer; text-decoration: underline;
}
.change-stub {
display: flex; align-items: center; gap: 6px;
font-size: 11px; color: #888;
padding: 4px 6px; border-bottom: 1px solid #f5f5f5;
}
.change-stub .stub-author { font-weight: 600; color: #555; }
.change-stub .stub-badge {
font-size: 9px; padding: 1px 5px; border-radius: 8px;
}
.change-stub .stub-badge.accepted { background: #dcfce7; color: #166534; }
.change-stub .stub-badge.declined { background: #f1f5f9; color: #94a3b8; }
.change-stub .stub-reason { flex: 1; color: #777; }
.change-stub .stub-source-link {
background: none; border: none; padding: 0;
font-size: 11px; color: #5b5bd6; cursor: pointer;
}
.contribution-cta {
border-top: 1px solid #e5e5e5;
background: #fafafa;
padding: 16px;
text-align: center;
}
.contribution-cta-count {
font-size: 13px; font-weight: 600; color: #1a1a1a;
}
.contribution-cta-desc {
font-size: 12px; color: #666; margin: 6px 0 12px;
}
.btn-start-contribution {
background: #1a1a1a; color: #fff;
border: none; border-radius: 6px;
padding: 8px 14px;
font-size: 13px; font-weight: 600; cursor: pointer;
}
/* ── DiffView ──────────────────────────────────────────────────── */
.diff-view-wrapper {
flex: 1; overflow-y: auto;
padding: 32px 48px;
}
.diff-view-empty {
font-size: 13px; color: #999;
text-align: center; padding: 24px;
}
.diff-tooltip {
background: #fff; border: 1px solid #e5e5e5;
border-radius: 8px; padding: 10px 12px;
box-shadow: 0 6px 24px rgba(0,0,0,0.12);
max-width: 320px; font-size: 12px;
z-index: 200;
}
.diff-tooltip-header {
display: flex; gap: 4px; flex-wrap: wrap;
margin-bottom: 6px;
}
.diff-tooltip-badge {
font-size: 10px; padding: 2px 7px; border-radius: 8px;
font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
}
.diff-tooltip-badge--manual { background: #f1f5f9; color: #475569; }
.diff-tooltip-badge--edited { background: #faf5ff; color: #7c3aed; }
.diff-tooltip-prompt {
border-top: 1px solid #f0f0ee;
padding-top: 6px;
font-size: 11px; color: #444;
}
.diff-tooltip-quote {
font-style: italic; color: #888; margin-bottom: 4px;
}
.diff-tooltip-reason {
border-top: 1px solid #f0f0ee;
padding-top: 6px; margin-top: 6px;
color: #555;
}
.diff-tooltip-reason-label {
display: inline-block; font-size: 9px; font-weight: 700;
color: #888; text-transform: uppercase; letter-spacing: 0.04em;
margin-right: 6px;
}
.diff-tooltip-no-context {
font-size: 11px; color: #aaa; font-style: italic;
}
/* ── Slice 3: the §10 PR flow surfaces ─────────────────────────────── */
.pr-modal { max-width: 640px; }
.pr-modal-warning {
background: #fef3c7; border: 1px solid #fbbf24;
padding: 10px 12px; border-radius: 6px; margin-bottom: 14px;
font-size: 12px; line-height: 1.5;
}
.pr-modal-warning p { margin: 0 0 6px 0; }
.modal-label {
display: block; font-size: 11px; font-weight: 600;
color: #555; margin: 10px 0 4px; text-transform: uppercase;
letter-spacing: 0.04em;
}
.modal-input, .modal-textarea {
width: 100%; padding: 7px 10px; font-size: 13px;
border: 1px solid #d1d5db; border-radius: 4px; box-sizing: border-box;
font-family: inherit;
}
.modal-textarea { resize: vertical; min-height: 100px; }
.btn-open-pr { background: #1a1a1a; color: #fff; border: none;
padding: 4px 10px; border-radius: 4px; font-size: 12px; cursor: pointer; }
.btn-open-pr:hover { background: #333; }
/* PR view header strip + two-column body */
.pr-view { display: flex; flex-direction: column; height: 100%; }
.pr-header {
display: grid; grid-template-columns: 1fr auto; gap: 16px;
padding: 14px 18px; border-bottom: 1px solid #e5e7eb;
background: #fafafa;
}
.pr-header-left { min-width: 0; }
.pr-breadcrumb { font-size: 11px; color: #666; margin-bottom: 6px; }
.pr-breadcrumb a { color: #5b5bd6; text-decoration: none; }
.pr-breadcrumb a:hover { text-decoration: underline; }
.pr-title { font-size: 18px; margin: 0 0 6px 0; }
.pr-description { font-size: 13px; color: #444; margin: 0 0 6px 0; line-height: 1.55; }
.pr-header-edit { display: flex; flex-direction: column; gap: 8px; }
.pr-header-right {
display: flex; flex-direction: column; align-items: flex-end; gap: 8px;
font-size: 12px;
}
.pr-state-banner {
padding: 3px 10px; border-radius: 12px;
font-size: 11px; font-weight: 600; text-transform: uppercase;
letter-spacing: 0.04em;
}
.pr-state-banner.open { background: #dcfce7; color: #14532d; }
.pr-state-banner.merged { background: #ddd6fe; color: #4c1d95; }
.pr-state-banner.withdrawn { background: #fef3c7; color: #78350f; }
.pr-state-banner.closed { background: #e5e7eb; color: #374151; }
.pr-counts { display: flex; gap: 12px; font-size: 11px; color: #555; }
.pr-count-flags { color: #b45309; font-weight: 600; font-size: 13px; }
.pr-supersedes { font-size: 11px; color: #6b7280; }
.pr-supersedes a { color: #5b5bd6; text-decoration: none; }
.pr-conflict-banner {
background: #fee2e2; border: 1px solid #fca5a5;
padding: 10px 12px; border-radius: 6px;
font-size: 12px; line-height: 1.5; max-width: 320px;
}
.pr-conflict-banner p { margin: 0 0 8px 0; }
.pr-actions { display: flex; gap: 8px; }
.pr-body { display: grid; grid-template-columns: 1fr 360px; flex: 1; overflow: hidden; }
.diff-mode-toolbar {
display: flex; gap: 12px; align-items: center;
padding: 6px 12px; border-bottom: 1px solid #f0f0ee;
font-size: 12px;
}
.diff-mode-toolbar .btn-link.active {
font-weight: 600; color: #1a1a1a;
}
.pr-diff-accent {
margin-left: auto;
font-size: 11px; color: #5b5bd6; font-weight: 600;
}
.diff-pane { flex: 1; overflow: auto; font-family: 'SF Mono', Monaco, monospace; font-size: 12px; }
.diff-pane.diff-split { display: grid; grid-template-columns: 1fr 1fr; gap: 1px; background: #e5e7eb; }
.diff-col { background: #fff; overflow: auto; }
.diff-col-header {
padding: 4px 10px; background: #f3f4f6; font-weight: 600;
font-size: 11px; color: #555; border-bottom: 1px solid #e5e7eb;
}
.diff-row {
display: flex; padding: 1px 8px;
white-space: pre-wrap; word-break: break-word; line-height: 1.5;
}
.diff-row.diff-equal { color: #374151; }
.diff-row.diff-del { background: #fee2e2; color: #7f1d1d; }
.diff-row.diff-add { background: #dcfce7; color: #14532d; }
.diff-row.diff-empty { background: #f9fafb; color: #d1d5db; }
.diff-marker { width: 16px; opacity: 0.5; user-select: none; }
.diff-text { flex: 1; }
/* PR conversation — chat + review interleaved */
.pr-conversation { padding: 10px 12px; overflow-y: auto; }
.pr-conv-disclosure {
display: flex; gap: 12px; font-size: 11px; color: #6b7280;
padding-bottom: 6px; border-bottom: 1px solid #f0f0ee; margin-bottom: 10px;
}
.thread-disclosure strong { color: #1a1a1a; }
.chat-feed { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 12px; }
.chat-msg {
display: flex; flex-direction: column; gap: 4px;
padding: 8px 10px; border-radius: 6px; background: #f9fafb;
font-size: 12px; line-height: 1.55;
}
.chat-msg-review { background: #ede9fe; border-left: 3px solid #7c3aed; }
.chat-msg-flag { background: #fef3c7; border-left: 3px solid #d97706; }
.chat-msg-new { box-shadow: 0 0 0 2px #c7d2fe; }
.chat-msg-header { display: flex; align-items: center; gap: 6px; font-size: 11px; color: #6b7280; }
.chat-msg-badge {
font-size: 9px; font-weight: 700; padding: 1px 5px; border-radius: 3px;
text-transform: uppercase; letter-spacing: 0.04em;
}
.chat-msg-badge.review { background: #7c3aed; color: #fff; }
.chat-msg-badge.flag { background: #d97706; color: #fff; }
.chat-msg-author { font-weight: 600; color: #1a1a1a; }
.chat-msg-new-pip { color: #5b5bd6; }
.chat-msg-quote {
background: #fff; border-left: 2px solid #d1d5db;
padding: 4px 8px; font-size: 11px; color: #6b7280;
margin: 0; white-space: pre-wrap;
}
.chat-msg-body { white-space: pre-wrap; }
.pr-review-composer {
border-top: 1px solid #e5e7eb; padding: 10px 12px;
background: #fafafa;
}
.pr-review-quote { font-size: 11px; color: #6b7280; margin-bottom: 6px; }
.pr-review-quote pre { background: #fff; padding: 4px 8px; border-radius: 4px; margin: 4px 0 0 0; }
/* ── Slice 5: §13 graduation dialog ──────────────────────────────────── */
.modal-wide { width: min(720px, 92vw); }
.modal-intro { margin: 0 0 16px 0; font-size: 13px; color: #4b5563; line-height: 1.55; }
.form-row { display: flex; flex-direction: column; gap: 4px; margin-bottom: 14px; }
.form-row label { font-weight: 600; font-size: 12px; color: #1a1a1a; }
.form-row input, .form-row textarea {
font: inherit; padding: 6px 8px; border: 1px solid #d1d5db; border-radius: 4px;
}
.field-help { font-size: 11px; color: #6b7280; margin: 2px 0 0 0; }
.field-error { font-size: 12px; color: #b91c1c; margin: 4px 0 0 0; }
.owner-list {
display: flex; flex-wrap: wrap; gap: 6px; min-height: 28px;
padding: 4px 0;
}
.owner-empty { font-size: 12px; color: #6b7280; font-style: italic; }
.owner-chip {
display: inline-flex; align-items: center; gap: 4px;
background: #eef2ff; color: #3730a3; padding: 2px 8px; border-radius: 99px;
font-size: 12px;
}
.owner-chip-x {
background: none; border: none; cursor: pointer; color: #6b7280;
font-size: 14px; line-height: 1; padding: 0 2px;
}
.owner-chip-x:hover { color: #b91c1c; }
.owner-picker { display: flex; gap: 6px; margin-top: 6px; }
.owner-picker input { flex: 1; }
.precondition-block { margin-top: 12px; padding: 10px; background: #fef2f2; border-radius: 6px; border: 1px solid #fecaca; }
.precondition-toggle {
background: none; border: none; cursor: pointer; color: #b91c1c; font-weight: 600;
font-size: 13px; padding: 0;
}
.precondition-popover { margin-top: 8px; display: flex; flex-direction: column; gap: 8px; }
.precondition-row {
display: flex; justify-content: space-between; align-items: center;
background: #fff; padding: 8px 10px; border-radius: 4px; border: 1px solid #f3f4f6;
}
.precondition-row-meta { font-size: 11px; color: #6b7280; }
.precondition-row-actions a { color: #5b5bd6; }
.precondition-help { font-size: 11px; color: #6b7280; margin: 4px 0 0 0; font-style: italic; }
.btn-graduate { margin-left: 6px; }
.step-stack { display: flex; flex-direction: column; gap: 6px; margin: 12px 0; }
.step-row {
display: grid; grid-template-columns: 24px 1fr auto; gap: 10px; align-items: center;
padding: 8px 10px; border-radius: 6px; background: #f9fafb; border: 1px solid #f3f4f6;
}
.step-row.step-running { background: #eff6ff; border-color: #bfdbfe; }
.step-row.step-done { background: #f0fdf4; border-color: #bbf7d0; }
.step-row.step-failed { background: #fef2f2; border-color: #fecaca; }
.step-row.step-not-reached { opacity: 0.45; }
.step-marker {
display: inline-block; width: 16px; height: 16px; border-radius: 50%;
background: #d1d5db;
}
.step-marker-pending { background: #d1d5db; }
.step-marker-running { background: #3b82f6; animation: pulse 1s ease-in-out infinite; }
.step-marker-done { background: #10b981; }
.step-marker-failed { background: #ef4444; }
.step-marker-not-reached { background: #e5e7eb; }
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } }
.step-label { font-weight: 600; font-size: 13px; color: #1a1a1a; }
.step-detail { font-size: 11px; color: #6b7280; margin-top: 2px; }
.step-status-pill {
font-size: 10px; font-weight: 700; padding: 2px 6px; border-radius: 3px;
text-transform: uppercase; letter-spacing: 0.04em;
}
.pill-pending { background: #e5e7eb; color: #4b5563; }
.pill-running { background: #3b82f6; color: #fff; }
.pill-done { background: #10b981; color: #fff; }
.pill-failed { background: #ef4444; color: #fff; }
.pill-not-reached { background: #e5e7eb; color: #9ca3af; }
.rollback-divider {
margin: 10px 0 6px 0; font-size: 11px; text-transform: uppercase;
letter-spacing: 0.06em; color: #b91c1c; font-weight: 700;
}
.what-happened {
margin-top: 14px; padding: 12px; background: #fef2f2;
border: 1px solid #fecaca; border-radius: 6px;
}
.what-happened h3 { margin: 0 0 6px 0; font-size: 14px; color: #991b1b; }
.what-happened p { margin: 0 0 6px 0; font-size: 13px; color: #4b5563; line-height: 1.55; }
.graduation-complete {
margin-top: 14px; padding: 12px; background: #f0fdf4;
border: 1px solid #bbf7d0; border-radius: 6px;
}
.graduation-complete h3 { margin: 0 0 6px 0; font-size: 14px; color: #166534; }
.graduation-complete p { margin: 0; font-size: 13px; color: #14532d; line-height: 1.55; }
.modal-progress-note { font-size: 12px; color: #6b7280; }
.modal-error {
padding: 8px 12px; background: #fef2f2; color: #991b1b;
border-top: 1px solid #fecaca; font-size: 12px;
}
.rfc-error-banner {
padding: 8px 12px; background: #fef2f2; color: #991b1b;
border-bottom: 1px solid #fecaca; font-size: 12px;
}
.branch-dropdown-section {
font-size: 10px; text-transform: uppercase; letter-spacing: 0.06em;
color: #6b7280; padding: 8px 10px 4px 10px; font-weight: 700;
}
.branch-dropdown-item.pre-graduation {
font-style: italic; color: #4b5563;
}
.branch-dropdown-item.pre-graduation .branch-meta {
font-size: 10px; color: #9ca3af; margin-left: auto;
}
/* ---- §15 / Slice 6: inbox, badge, toasts ---- */
.inbox-trigger {
position: relative; background: transparent; border: 1px solid #e5e7eb;
border-radius: 6px; padding: 4px 10px; cursor: pointer; font-size: 16px;
margin-right: 12px;
}
.inbox-trigger:hover { background: #f9fafb; }
.inbox-trigger .badge {
position: absolute; top: -6px; right: -6px;
background: #dc2626; color: white; font-size: 10px;
border-radius: 999px; padding: 1px 5px; font-weight: 700;
min-width: 16px; text-align: center;
}
.inbox-overlay {
position: fixed; inset: 0; background: rgba(0,0,0,0.25);
display: flex; align-items: flex-start; justify-content: center;
padding-top: 60px; z-index: 100;
}
.inbox-panel {
background: white; border: 1px solid #e5e7eb; border-radius: 8px;
width: 720px; max-width: 90vw; max-height: 80vh;
display: flex; flex-direction: column; box-shadow: 0 12px 32px rgba(0,0,0,0.18);
}
.inbox-header {
display: flex; align-items: center; justify-content: space-between;
padding: 12px 16px; border-bottom: 1px solid #e5e7eb;
}
.inbox-header h2 { margin: 0; font-size: 16px; }
.inbox-filters {
display: flex; gap: 8px; flex-wrap: wrap;
padding: 10px 16px; border-bottom: 1px solid #f3f4f6; align-items: center;
}
.inbox-filters .chip {
font-size: 12px; padding: 4px 8px; background: #f9fafb;
border: 1px solid #e5e7eb; border-radius: 999px;
display: inline-flex; align-items: center; gap: 4px;
}
.inbox-filters .chip input[type=checkbox] { margin-right: 2px; }
.inbox-filters select.chip { padding: 4px 8px; }
.inbox-body { overflow-y: auto; flex: 1; }
.inbox-list { list-style: none; margin: 0; padding: 0; }
.inbox-row { border-bottom: 1px solid #f3f4f6; }
.inbox-row.unread { background: #fffbeb; }
.inbox-row-link {
display: flex; align-items: center; gap: 10px; padding: 10px 16px;
text-decoration: none; color: inherit;
}
.inbox-row-link:hover { background: #f9fafb; }
.inbox-cat {
font-size: 9px; text-transform: uppercase; letter-spacing: 0.05em;
padding: 2px 6px; border-radius: 4px; font-weight: 700;
}
.inbox-cat.cat-personal-direct { background: #fef3c7; color: #92400e; }
.inbox-cat.cat-structural { background: #dbeafe; color: #1e40af; }
.inbox-cat.cat-churn { background: #f3f4f6; color: #4b5563; }
.inbox-summary { flex: 1; font-size: 13px; }
.inbox-bundle-count {
font-size: 11px; color: #6b7280;
background: #f3f4f6; padding: 1px 6px; border-radius: 999px;
}
.inbox-when { font-size: 11px; color: #9ca3af; }
.toast-host {
position: fixed; right: 16px; bottom: 16px;
display: flex; flex-direction: column; gap: 8px; z-index: 200;
}
.toast {
padding: 10px 14px; background: white; border: 1px solid #e5e7eb;
border-left: 4px solid #6b7280; border-radius: 6px;
box-shadow: 0 4px 12px rgba(0,0,0,0.08); font-size: 13px;
max-width: 360px; cursor: pointer;
}
.toast.cat-personal-direct { border-left-color: #d97706; }
.toast.cat-structural { border-left-color: #2563eb; }
.toast.cat-churn { border-left-color: #6b7280; }
/* ── Slice 7: §14 chrome + /settings/notifications + /admin ──────────── */
/* Header chrome — the persistent §14.3 About link plus the Settings and
Admin entrypoints. The header's job is to be invisible until the user
reaches for it, so these read as quiet text links rather than buttons. */
.header-about, .header-settings, .header-admin {
color: #ddd; text-decoration: none;
font-size: 12px; letter-spacing: 0.02em;
padding: 4px 8px; border-radius: 4px;
}
.header-about:hover, .header-settings:hover, .header-admin:hover {
color: #fff; background: rgba(255,255,255,0.08);
}
.header-admin {
color: #fbbf24; /* admin link sits a notch warmer to signal authority */
}
/* /philosophy — the §14.2 read surface. The body uses the shared
markdown styling; the header is a thin chrome strip. */
.chrome-pane {
flex: 1; min-width: 0; overflow: auto;
padding: 0; background: #fff;
}
.philosophy-page {
max-width: 760px; margin: 0 auto;
padding: 24px 32px 64px;
}
.philosophy-header {
display: flex; align-items: center; gap: 12px;
padding: 12px 0 18px;
border-bottom: 1px solid #f0f0ee;
margin-bottom: 28px;
}
.philosophy-back {
border: none; background: none; cursor: pointer;
color: #4b5563; font-size: 13px;
padding: 4px 8px; border-radius: 4px;
}
.philosophy-back:hover { background: #f3f4f6; color: #111; }
.philosophy-title {
font-size: 13px; color: #6b7280;
text-transform: uppercase; letter-spacing: 0.08em;
}
.philosophy-signin {
margin-left: auto;
font-size: 13px; color: #4b5563; text-decoration: none;
}
.philosophy-signin:hover { color: #111; text-decoration: underline; }
.philosophy-body h1 {
font-size: 28px; font-weight: 700; margin: 0 0 24px;
letter-spacing: -0.01em;
}
.philosophy-body h2 {
font-size: 19px; font-weight: 600; margin: 36px 0 12px;
color: #111;
}
.philosophy-body h3 {
font-size: 15px; font-weight: 600; margin: 24px 0 10px;
}
.philosophy-body p {
margin: 0 0 16px; line-height: 1.65; font-size: 15px; color: #1f2937;
}
.philosophy-body em { color: #4b5563; font-style: italic; }
.philosophy-body strong { color: #111; }
.philosophy-body ul, .philosophy-body ol {
margin: 0 0 20px; padding-left: 24px;
}
.philosophy-body li { margin-bottom: 8px; line-height: 1.6; }
.philosophy-body hr {
border: none; border-top: 1px solid #e5e7eb; margin: 32px 0;
}
.philosophy-body code {
background: #f3f4f6; padding: 1px 5px; border-radius: 3px;
font-size: 0.92em;
}
/* Richer landing page (§14.1) — adds the three-item deck under the
pitch. The .landing container handles flex centering; the new
content lives inside .landing-inner. */
.landing-inner {
max-width: 620px;
display: flex; flex-direction: column; align-items: center;
}
.landing-deck {
list-style: none; padding: 0;
margin: 48px 0 0; text-align: left;
display: flex; flex-direction: column; gap: 18px;
border-top: 1px solid #e5e7eb; padding-top: 32px;
max-width: 540px;
}
.landing-deck li {
font-size: 14px; line-height: 1.6; color: #374151;
}
.landing-deck strong { color: #111; }
/* /settings/notifications */
.settings-page {
max-width: 720px; margin: 0 auto;
padding: 24px 32px 64px;
}
.settings-header h1 {
margin: 0 0 6px; font-size: 24px; font-weight: 700; letter-spacing: -0.01em;
}
.settings-sub {
color: #6b7280; font-size: 13px; margin: 0 0 24px;
line-height: 1.5;
}
.settings-section {
border: 1px solid #e5e7eb; border-radius: 8px;
padding: 20px 24px; margin-bottom: 16px; background: #fff;
}
.settings-section h2 {
margin: 0 0 4px; font-size: 15px; font-weight: 600;
}
.settings-section-body { display: flex; flex-direction: column; gap: 12px; }
.settings-row { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; }
.quiet-hours-row label {
display: flex; flex-direction: column; gap: 4px;
font-size: 12px; color: #6b7280;
}
.quiet-hours-row input, .quiet-hours-row select {
border: 1px solid #d1d5db; border-radius: 6px;
padding: 6px 10px; font-size: 13px;
background: white; color: #111;
}
.settings-note { font-size: 12px; color: #6b7280; margin: 0; }
.settings-note.warning { color: #b91c1c; }
.toggle-row {
display: flex; align-items: flex-start; gap: 12px;
cursor: pointer; padding: 10px 0;
border-top: 1px solid #f3f4f6;
}
.toggle-row:first-child { border-top: none; padding-top: 0; }
.toggle-row.disabled { cursor: not-allowed; opacity: 0.6; }
.toggle-row input[type=checkbox] { margin-top: 3px; }
.toggle-text { display: flex; flex-direction: column; gap: 2px; }
.toggle-label { font-size: 14px; font-weight: 500; color: #111; }
.toggle-desc { font-size: 12px; color: #6b7280; line-height: 1.5; }
.btn-primary {
background: #111; color: #fff; border: none;
padding: 7px 14px; border-radius: 6px; font-size: 13px; cursor: pointer;
}
.btn-primary:hover { background: #333; }
.btn-primary:disabled { background: #9ca3af; cursor: not-allowed; }
.btn-link-muted {
background: none; border: none; cursor: pointer;
color: #6b7280; font-size: 12px; padding: 4px 6px;
}
.btn-link-muted:hover { color: #111; text-decoration: underline; }
.settings-table, .admin-table {
width: 100%; border-collapse: collapse;
font-size: 13px;
}
.settings-table th, .admin-table th {
text-align: left; padding: 6px 8px;
font-size: 11px; text-transform: uppercase;
color: #6b7280; letter-spacing: 0.05em; font-weight: 600;
border-bottom: 1px solid #e5e7eb;
}
.settings-table td, .admin-table td {
padding: 8px 8px; border-bottom: 1px solid #f3f4f6;
}
.settings-table select { font-size: 13px; padding: 3px 6px; }
.set-by {
font-size: 10px; text-transform: uppercase; letter-spacing: 0.05em;
padding: 2px 6px; border-radius: 4px; font-weight: 600;
}
.set-by-auto { background: #f3f4f6; color: #6b7280; }
.set-by-explicit { background: #dbeafe; color: #1e40af; }
.mutes-list { list-style: none; padding: 0; margin: 8px 0 0; }
.mutes-row {
display: flex; align-items: center; gap: 10px;
padding: 6px 8px; border-bottom: 1px solid #f3f4f6;
font-size: 13px;
}
.mute-handle { font-weight: 500; color: #111; }
.mute-when { font-size: 11px; margin-left: auto; }
.mute-typeahead { position: relative; }
.mute-typeahead input {
width: 100%; box-sizing: border-box;
border: 1px solid #d1d5db; border-radius: 6px;
padding: 7px 10px; font-size: 13px; outline: none;
}
.mute-typeahead input:focus { border-color: #111; }
.mute-typeahead-results {
position: absolute; top: 100%; left: 0; right: 0;
background: white; border: 1px solid #d1d5db; border-radius: 6px;
box-shadow: 0 4px 12px rgba(0,0,0,0.08);
margin-top: 4px; padding: 4px 0; z-index: 10;
list-style: none;
}
.mute-typeahead-results button {
display: flex; gap: 10px; align-items: center;
width: 100%; padding: 6px 10px;
background: none; border: none; text-align: left; cursor: pointer;
font-size: 13px;
}
.mute-typeahead-results button:hover { background: #f9fafb; }
/* /admin */
.admin-page {
display: flex; height: 100%;
width: 100%;
}
.admin-rail {
width: 220px; flex-shrink: 0;
background: #f9fafb; border-right: 1px solid #e5e7eb;
padding: 24px 16px;
}
.admin-rail h2 {
font-size: 13px; color: #6b7280;
text-transform: uppercase; letter-spacing: 0.08em;
margin: 0 0 12px;
}
.admin-rail ul { list-style: none; padding: 0; margin: 0 0 24px; }
.admin-rail li { margin-bottom: 2px; }
.admin-rail-link {
display: block; padding: 6px 10px;
font-size: 13px; color: #374151; text-decoration: none;
border-radius: 4px;
}
.admin-rail-link:hover { background: #f3f4f6; }
.admin-rail-link.active { background: #111; color: #fff; }
.admin-rail-note {
font-size: 11px; color: #6b7280; line-height: 1.5;
}
.admin-content {
flex: 1; min-width: 0;
padding: 28px 36px;
overflow: auto;
}
.admin-tab-header h2 {
margin: 0 0 4px; font-size: 18px; font-weight: 700;
}
.admin-tab-header p { margin: 0 0 24px; font-size: 13px; }
.admin-section-h {
font-size: 13px; text-transform: uppercase;
letter-spacing: 0.05em; color: #6b7280;
margin: 24px 0 8px;
}
.audit-filters {
display: flex; gap: 8px; margin-bottom: 18px; flex-wrap: wrap;
}
.audit-filters input, .audit-filters select {
border: 1px solid #d1d5db; border-radius: 6px;
padding: 5px 9px; font-size: 13px; background: white;
}
.audit-table code {
font-size: 11px; background: #f3f4f6;
padding: 1px 5px; border-radius: 3px;
}
.user-cell { display: flex; flex-direction: column; gap: 1px; }
.user-handle { font-weight: 500; color: #111; }
.mute-toggle {
display: inline-flex; align-items: center; gap: 6px;
font-size: 13px; cursor: pointer;
}
.grad-queue { list-style: none; padding: 0; margin: 8px 0 24px; }
.grad-queue li { padding: 8px 0; border-bottom: 1px solid #f3f4f6; }
.grad-queue-link { color: #111; text-decoration: none; font-size: 14px; }
.grad-queue-link:hover strong { text-decoration: underline; }
.muted { color: #6b7280; }
.error { color: #b91c1c; }