rubriq / web /styles.css
devadit15's picture
Claude Fable 5
Instrument-panel redesign + Motion layer + critique fixes
37afc86
Raw History Blame Contribute Delete
21.7 kB
/* Rubriq — forensic lab bench: verdicts in green ink on white paper.
Register: product. Strategy: restrained. See DESIGN.md. */
/* ---------- fonts (self-hosted, latin subsets) ---------- */
@font-face {
font-family: "IBM Plex Sans";
src: url("fonts/plexsans-var-latin.woff2") format("woff2");
font-weight: 100 700;
font-display: swap;
}
@font-face {
font-family: "JetBrains Mono";
src: url("fonts/jbmono-var-latin.woff2") format("woff2");
font-weight: 100 800;
font-display: swap;
}
/* ---------- tokens ---------- */
:root {
--bg: oklch(1.000 0.000 0);
--surface: oklch(0.972 0.004 140);
--surface-2: oklch(0.945 0.006 140);
--ink: oklch(0.230 0.015 140);
--muted: oklch(0.470 0.018 140);
--line: oklch(0.885 0.008 140);
--primary: oklch(0.480 0.100 140);
--primary-deep:oklch(0.400 0.095 140);
--primary-ink: oklch(0.980 0.005 140);
--primary-tint:oklch(0.950 0.020 140);
--accent: oklch(0.400 0.075 255);
--accent-tint: oklch(0.945 0.015 255);
--good: oklch(0.480 0.100 140);
--warn: oklch(0.560 0.120 75);
--warn-deep: oklch(0.450 0.100 75);
--warn-tint: oklch(0.955 0.025 85);
--bad: oklch(0.505 0.160 25);
--bad-tint: oklch(0.955 0.020 25);
--judge: oklch(0.400 0.075 255);
/* instrument console (input pane) — deep green-tinted near-black */
--console: oklch(0.180 0.020 150);
--console-2: oklch(0.225 0.022 150); /* input wells */
--console-line: oklch(0.330 0.022 150);
--console-ink: oklch(0.935 0.008 140);
--console-mut: oklch(0.720 0.020 145);
--led: oklch(0.760 0.150 148); /* phosphor green: LED, focus, fills */
--led-dim: oklch(0.320 0.060 148); /* selected-state well */
--sans: "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
--mono: "JetBrains Mono", ui-monospace, "Cascadia Code", Consolas, monospace;
--r-ctl: 6px;
--r-panel: 10px;
--ease: cubic-bezier(0.22, 1, 0.36, 1);
--z-dropdown: 10;
--z-sticky: 20;
--z-toast: 40;
}
/* ---------- reset & base ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { height: 100%; }
body {
margin: 0;
min-height: 100%;
background: var(--bg);
color: var(--ink);
font: 400 15px/1.6 var(--sans);
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
}
h1, h2, h3 { text-wrap: balance; margin: 0; }
p { margin: 0; }
a { color: var(--primary); }
button { font: inherit; }
::selection { background: var(--primary-tint); }
:is(button, a, input, textarea, summary):focus-visible {
outline: 2px solid var(--primary);
outline-offset: 2px;
border-radius: var(--r-ctl);
}
/* ---------- top bar ---------- */
.topbar {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
padding: 0 24px;
height: 56px;
border-bottom: 1px solid var(--line);
background: var(--bg);
position: sticky;
top: 0;
z-index: var(--z-sticky);
}
.brand { display: flex; align-items: baseline; gap: 12px; min-width: 0; }
.wordmark {
font-size: 20px;
font-weight: 650;
letter-spacing: -0.02em;
color: var(--primary-deep);
}
.brand-note {
font-size: 13px;
color: var(--muted);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.topbar-right { display: flex; align-items: center; gap: 16px; }
.top-link {
font-size: 13.5px;
font-weight: 500;
color: var(--ink);
text-decoration: none;
border-bottom: 1px solid var(--line);
padding-bottom: 1px;
}
.top-link:hover { border-bottom-color: var(--ink); }
.engine-pill {
display: inline-flex;
align-items: center;
gap: 7px;
font-size: 12.5px;
font-weight: 500;
color: var(--muted);
border: 1px solid var(--line);
border-radius: 999px;
padding: 4px 11px 4px 9px;
background: var(--surface);
}
.engine-dot {
width: 7px; height: 7px; border-radius: 50%;
background: var(--muted);
transition: background 200ms var(--ease);
}
.engine-pill[data-state="ready"] .engine-dot { background: var(--good); }
.engine-pill[data-state="ready"] { color: var(--ink); }
.engine-pill[data-state="waking"] .engine-dot {
background: var(--warn);
animation: pulse 1.4s ease-in-out infinite;
}
.engine-pill[data-state="down"] .engine-dot { background: var(--bad); }
@keyframes pulse { 50% { opacity: 0.35; } }
/* ---------- layout ---------- */
.split {
display: grid;
grid-template-columns: minmax(370px, 440px) 1fr;
min-height: calc(100vh - 57px);
}
.pane-input {
background: var(--console);
color: var(--console-ink);
padding: 28px 24px 32px;
position: sticky;
top: 57px;
height: calc(100vh - 57px);
overflow-y: auto;
overscroll-behavior: contain;
}
.pane-report {
padding: 0 40px 64px;
min-width: 0;
position: relative;
}
#reportPane { padding-top: 29px; }
/* scroll-linked reading progress (Motion scroll()) */
.read-progress {
position: sticky;
top: 57px;
height: 3px;
margin: 0 -40px;
background: transparent;
z-index: var(--z-sticky);
}
.read-progress-fill {
height: 100%;
background: var(--primary);
transform: scaleX(0);
transform-origin: left;
}
/* ---------- form (instrument console) ---------- */
.field { margin-bottom: 18px; }
.field label,
fieldset.field legend {
display: block;
font-family: var(--mono);
font-size: 11px;
font-weight: 600;
letter-spacing: 0.09em;
text-transform: uppercase;
margin-bottom: 7px;
color: var(--console-mut);
}
.field .opt {
font-family: var(--sans);
font-weight: 400;
letter-spacing: 0;
text-transform: none;
color: var(--console-mut);
margin-left: 4px;
}
textarea, input[type="text"], input:not([type]) {
width: 100%;
border: 1px solid var(--console-line);
border-radius: var(--r-ctl);
background: var(--console-2);
color: var(--console-ink);
padding: 10px 12px;
font: 400 13.5px/1.6 var(--sans);
letter-spacing: 0.01em;
transition: border-color 150ms var(--ease), background 150ms var(--ease);
}
textarea { resize: vertical; min-height: 72px; }
textarea::placeholder, input::placeholder { color: var(--console-mut); }
textarea:hover, input:hover { border-color: oklch(0.45 0.03 150); }
textarea:focus-visible, input:focus-visible {
outline: 2px solid var(--led);
outline-offset: 0;
border-color: transparent;
}
.pane-input :is(button, a, input, textarea, summary):focus-visible {
outline-color: var(--led);
}
/* model picker: two searchable comboboxes */
fieldset.field-model { border: 0; padding: 0; margin: 0 0 18px; }
fieldset.field-model legend { padding: 0; }
.combo-row {
display: grid;
grid-template-columns: 1fr 1.35fr;
gap: 8px;
}
.combo { position: relative; }
.combo input { padding-right: 30px; }
.combo-toggle {
position: absolute;
top: 1px; right: 1px; bottom: 1px;
width: 28px;
border: 0;
background: transparent;
color: var(--console-mut);
font-size: 11px;
cursor: pointer;
border-radius: 0 var(--r-ctl) var(--r-ctl) 0;
}
.combo-toggle:hover { color: var(--console-ink); }
.combo-list {
position: absolute;
top: calc(100% + 4px);
left: 0; right: 0;
z-index: var(--z-dropdown);
margin: 0;
padding: 4px;
list-style: none;
background: var(--console-2);
border: 1px solid var(--console-line);
border-radius: var(--r-ctl);
box-shadow: 0 10px 28px oklch(0 0 0 / 0.45);
/* exactly 4 rows visible; the rest scrolls */
max-height: calc(4 * 32px + 8px);
overflow-y: auto;
overscroll-behavior: contain;
}
.combo-list li {
height: 32px;
display: flex;
align-items: center;
gap: 8px;
padding: 0 9px;
font-size: 13px;
color: var(--console-ink);
border-radius: 4px;
cursor: pointer;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.combo-list li .co-provider {
font-size: 11.5px;
color: var(--console-mut);
margin-left: auto;
flex-shrink: 0;
}
.combo-list li:hover { background: oklch(0.28 0.025 150); }
.combo-list li[aria-selected="true"] { background: var(--led-dim); color: var(--led); }
.combo-list li.co-empty { color: var(--console-mut); cursor: default; }
.combo-list li.co-empty:hover { background: transparent; }
/* tone selector */
fieldset.field-tone { border: 0; padding: 0; margin: 0 0 18px; }
fieldset.field-tone legend { padding: 0; }
.tone-row { display: flex; flex-wrap: wrap; gap: 8px; }
.tone-chip input {
position: absolute;
opacity: 0;
pointer-events: none;
}
label.tone-chip {
/* undo the etched-label style .field label applies; chips are controls */
font-family: var(--sans);
font-size: 12.5px;
font-weight: 500;
letter-spacing: 0;
text-transform: none;
color: var(--console-ink);
margin-bottom: 0;
display: inline-block;
}
.tone-chip span {
display: inline-block;
border: 1px solid var(--console-line);
background: transparent;
color: var(--console-ink);
border-radius: 999px;
padding: 5px 14px;
cursor: pointer;
transition: border-color 150ms var(--ease), background 150ms var(--ease), color 150ms var(--ease);
}
.tone-chip span:hover { border-color: var(--led); }
.tone-chip input:checked + span {
background: var(--led-dim);
border-color: var(--led);
color: var(--led);
font-weight: 600;
}
.tone-chip input:focus-visible + span {
outline: 2px solid var(--led);
outline-offset: 2px;
}
.actions { display: flex; gap: 10px; margin: 24px 0 0; }
.btn {
border-radius: var(--r-ctl);
padding: 10px 18px;
font-size: 14px;
font-weight: 650;
cursor: pointer;
border: 1px solid transparent;
transition: background 150ms var(--ease), border-color 150ms var(--ease), opacity 150ms var(--ease);
}
.btn:disabled { opacity: 0.45; cursor: not-allowed; }
.btn-primary {
background: var(--led);
color: oklch(0.16 0.02 150);
flex: 1;
letter-spacing: 0.01em;
}
.btn-primary:hover:not(:disabled) { background: oklch(0.82 0.16 148); }
.btn-primary:active:not(:disabled) { background: oklch(0.70 0.14 148); }
.btn-ghost {
background: transparent;
color: var(--console-ink);
border-color: var(--console-line);
}
.btn-ghost:hover:not(:disabled) { border-color: var(--console-mut); }
.samples { margin-top: 28px; padding-top: 20px; border-top: 1px solid var(--console-line); }
.samples-label {
font-family: var(--mono);
font-size: 11px;
font-weight: 600;
letter-spacing: 0.09em;
text-transform: uppercase;
color: var(--console-mut);
}
.samples-row { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.chip {
border: 1px solid var(--console-line);
background: transparent;
color: var(--console-ink);
border-radius: 999px;
padding: 5px 13px;
font-size: 12.5px;
font-weight: 500;
cursor: pointer;
transition: border-color 150ms var(--ease), color 150ms var(--ease);
}
.chip:hover { border-color: var(--led); color: var(--led); }
/* ---------- report pane: states ---------- */
.report-empty { max-width: 62ch; margin-top: 8vh; }
.report-empty h1 {
font-size: 24px;
font-weight: 650;
letter-spacing: -0.015em;
line-height: 1.25;
margin-bottom: 14px;
}
.report-empty p { color: var(--muted); margin-bottom: 12px; max-width: 58ch; }
.report-empty .empty-honesty {
margin-top: 28px;
font-size: 13.5px;
color: var(--muted);
border: 1px solid var(--line);
border-radius: var(--r-panel);
padding: 14px 16px;
background: var(--surface);
}
.report-empty .empty-honesty strong { color: var(--ink); font-weight: 600; }
.report-error {
max-width: 56ch;
margin-top: 8vh;
border: 1px solid var(--line);
border-radius: var(--r-panel);
padding: 20px 22px;
background: var(--bad-tint);
}
.report-error h2 { font-size: 16px; margin-bottom: 8px; }
.report-error p { font-size: 14px; color: var(--ink); }
.report-error code { font-family: var(--mono); font-size: 12.5px; }
/* skeleton */
.skel-row {
height: 74px;
border: 1px solid var(--line);
border-radius: var(--r-panel);
margin-bottom: 12px;
position: relative;
overflow: hidden;
background: var(--surface);
}
.skel-row::after {
content: "";
position: absolute;
inset: 0;
background: linear-gradient(100deg, transparent 30%, oklch(1 0 0 / 0.65) 50%, transparent 70%);
transform: translateX(-100%);
animation: shimmer 1.6s var(--ease) infinite;
}
@keyframes shimmer { to { transform: translateX(100%); } }
.skel-note {
font-size: 13.5px; color: var(--muted);
margin: 6px 0 18px;
font-variant-numeric: tabular-nums;
}
/* ---------- report ---------- */
.report { max-width: 860px; }
.report-head {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 24px;
padding-bottom: 24px;
margin-bottom: 8px;
border-bottom: 1px solid var(--line);
}
.report-head-left { min-width: 0; }
.report-title {
font-size: 24px;
font-weight: 650;
letter-spacing: -0.015em;
margin-bottom: 10px;
}
.task-line {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px;
font-size: 13px;
color: var(--muted);
}
.task-chip {
border: 1px solid var(--primary);
color: var(--primary-deep);
border-radius: 999px;
padding: 2px 11px;
font-size: 12.5px;
font-weight: 600;
}
.signals { margin-top: 10px; font-size: 13px; color: var(--muted); }
.signals summary { cursor: pointer; user-select: none; }
.signals summary:hover { color: var(--ink); }
.signals ul { margin: 8px 0 0; padding-left: 18px; }
.signals li { margin-bottom: 2px; }
.overall {
display: flex;
align-items: center;
gap: 14px;
flex-shrink: 0;
text-align: right;
}
.overall-text { order: -1; }
.gauge { display: block; }
.gauge .gauge-track { stroke: var(--surface-2); }
.gauge .gauge-fill {
stroke-linecap: round;
transform: rotate(-90deg);
transform-origin: 50% 50%;
}
.gauge-good { stroke: var(--good); }
.gauge-warn { stroke: var(--warn); }
.gauge-bad { stroke: var(--bad); }
.gauge-num {
font-family: var(--mono);
font-size: 24px;
font-weight: 600;
font-variant-numeric: tabular-nums;
fill: var(--ink);
}
.overall-band { font-size: 13.5px; font-weight: 650; }
.overall-note {
font-size: 12px;
color: var(--muted);
max-width: 26ch;
margin-top: 5px;
line-height: 1.45;
}
.band-good { color: var(--good); }
.band-warn { color: var(--warn-deep); }
.band-bad { color: var(--bad); }
/* honesty notes */
.honesty {
margin: 16px 0 24px;
border: 1px solid var(--line);
border-radius: var(--r-panel);
background: var(--surface);
padding: 12px 16px;
font-size: 13px;
color: var(--muted);
}
.honesty-title {
font-weight: 600;
color: var(--ink);
font-size: 13px;
margin-bottom: 6px;
}
.honesty ul { margin: 0; padding-left: 18px; }
.honesty li { margin-bottom: 4px; }
.honesty li:last-child { margin-bottom: 0; }
/* section headings inside report */
.report h2.sect {
font-size: 16px;
font-weight: 650;
margin: 40px 0 16px;
}
.report h2.sect .count { color: var(--muted); font-weight: 500; font-size: 13.5px; }
/* ---------- verdict rows ---------- */
.verdict {
border: 1px solid var(--line);
border-radius: var(--r-panel);
margin-bottom: 10px;
background: var(--bg);
overflow: hidden;
}
.verdict summary {
list-style: none;
cursor: pointer;
padding: 14px 16px;
display: block;
}
.verdict summary::-webkit-details-marker { display: none; }
.verdict summary:hover { background: var(--surface); }
.verdict[open] summary { border-bottom: 1px solid var(--line); }
.v-top {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 8px;
}
.v-name { font-size: 14.5px; font-weight: 600; flex: 1; min-width: 0; }
.v-caret {
color: var(--muted);
font-size: 11px;
transition: transform 180ms var(--ease);
}
.verdict[open] .v-caret { transform: rotate(90deg); }
.badge {
font-size: 10.5px;
font-weight: 600;
letter-spacing: 0.05em;
border-radius: 4px;
padding: 2px 7px;
border: 1px solid;
white-space: nowrap;
}
.badge-proxy { color: var(--warn-deep); border-color: var(--warn); background: var(--warn-tint); }
.badge-judge { color: var(--judge); border-color: var(--judge); background: var(--accent-tint); }
.badge-family { color: var(--accent); border-color: var(--accent); background: var(--accent-tint); }
.v-meter {
display: flex;
align-items: center;
gap: 12px;
}
.v-score {
font-family: var(--mono);
font-size: 15px;
font-weight: 600;
font-variant-numeric: tabular-nums;
min-width: 42px;
}
.v-score.skipped { color: var(--muted); font-weight: 400; }
.v-track {
flex: 1;
height: 4px;
border-radius: 2px;
background: var(--surface-2);
overflow: hidden;
}
.v-fill {
height: 100%;
border-radius: 2px;
width: 100%;
transform: scaleX(0);
transform-origin: left;
/* fill animation driven by Motion spring in app.js */
}
.fill-good { background: var(--good); }
.fill-warn { background: var(--warn); }
.fill-bad { background: var(--bad); }
.v-bandword {
font-size: 12px;
font-weight: 600;
min-width: 52px;
text-align: right;
}
.v-verdict {
margin-top: 9px;
font-size: 13.5px;
color: var(--muted);
line-height: 1.5;
}
.v-body { padding: 16px; }
.v-source {
font-size: 12px;
color: var(--muted);
margin-bottom: 14px;
}
.v-source::before { content: "method · "; font-weight: 600; }
.v-group-title {
font-size: 12.5px;
font-weight: 650;
margin: 14px 0 8px;
}
.v-group-title.t-good { color: var(--good); }
.v-group-title.t-bad { color: var(--bad); }
.v-strength {
font-size: 13.5px;
margin-bottom: 4px;
padding-left: 18px;
position: relative;
}
.v-strength::before {
content: "✓";
position: absolute; left: 0;
color: var(--good);
font-weight: 600;
}
.finding { margin-bottom: 14px; }
.finding-head {
display: flex;
align-items: baseline;
gap: 8px;
margin-bottom: 6px;
}
.finding-mode {
font-family: var(--mono);
font-size: 11px;
font-weight: 600;
color: var(--bad);
white-space: nowrap;
}
.finding-detail { font-size: 13.5px; line-height: 1.55; }
.evidence {
border: 1px solid var(--line);
border-radius: var(--r-ctl);
background: var(--surface-2);
padding: 9px 12px;
margin: 6px 0 0;
font-family: var(--mono);
font-size: 12.5px;
line-height: 1.6;
color: var(--ink);
overflow-x: auto;
}
.evidence .ev-tag {
display: block;
font-family: var(--sans);
font-size: 11px;
font-weight: 600;
color: var(--muted);
margin-bottom: 3px;
}
/* skipped parameters */
.verdict.is-skipped summary { cursor: default; }
.verdict.is-skipped .v-verdict { color: var(--muted); }
.verdict.is-skipped .v-name { color: var(--muted); font-weight: 500; }
/* ---------- repair prompts ---------- */
.repair {
border: 1px solid var(--line);
border-radius: var(--r-panel);
margin-bottom: 14px;
overflow: hidden;
}
.repair-head { padding: 14px 16px 0; }
.repair-title-row {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 8px;
}
.repair-title { font-size: 14.5px; font-weight: 650; flex: 1; }
.repair-diagnosis {
font-size: 13.5px;
color: var(--muted);
line-height: 1.55;
margin-bottom: 12px;
max-width: 70ch;
}
.repair-block { border-top: 1px solid var(--line); }
.repair-block-bar {
display: flex;
justify-content: flex-end;
padding: 8px 12px;
background: var(--surface-2);
}
.repair-pre {
margin: 0;
background: var(--surface-2);
padding: 0 16px 14px;
font-family: var(--mono);
font-size: 12.5px;
line-height: 1.65;
white-space: pre-wrap;
overflow-wrap: break-word;
max-height: 320px;
overflow-y: auto;
}
.copy-btn {
border: 1px solid var(--line);
background: var(--bg);
color: var(--ink);
border-radius: var(--r-ctl);
font-size: 12px;
font-weight: 600;
padding: 5px 12px;
cursor: pointer;
transition: border-color 150ms var(--ease), color 150ms var(--ease);
}
.copy-btn:hover { border-color: var(--primary); color: var(--primary-deep); }
.copy-btn.copied { color: var(--good); border-color: var(--good); }
.repair-foot {
padding: 8px 16px;
border-top: 1px solid var(--line);
font-size: 12px;
color: var(--muted);
}
.repair-foot::before { content: "technique · "; font-weight: 600; }
.no-repairs {
border: 1px solid var(--line);
border-radius: var(--r-panel);
background: var(--primary-tint);
color: var(--primary-deep);
font-size: 14px;
padding: 16px 18px;
}
/* ---------- reveal motion ----------
Reveals are driven by Motion (vendor/motion.js) in app.js; elements are
visible by default so a script failure never blanks the report. */
.sr-only {
position: absolute;
width: 1px; height: 1px;
margin: -1px; padding: 0;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
border: 0;
}
/* ---------- toast ---------- */
.toast {
position: fixed;
bottom: 24px;
left: 50%;
transform: translateX(-50%);
z-index: var(--z-toast);
background: var(--ink);
color: var(--bg);
font-size: 13.5px;
font-weight: 500;
border-radius: 8px;
padding: 10px 18px;
box-shadow: 0 6px 24px oklch(0 0 0 / 0.18);
}
/* ---------- responsive ---------- */
@media (max-width: 960px) {
.split { grid-template-columns: 1fr; }
.pane-input {
position: static;
height: auto;
overflow: visible;
}
.pane-report { padding: 0 20px 48px; }
#reportPane { padding-top: 21px; }
.read-progress { margin: 0 -20px; }
.report-head { flex-direction: column; gap: 14px; }
.overall { text-align: left; }
.overall-text { order: 1; }
.overall-note { max-width: 60ch; }
.brand-note { display: none; }
}
/* ---------- reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
/* JS motion is gated on the same query in app.js; this covers the CSS side */
.skel-row::after { animation: none; }
.engine-pill[data-state="waking"] .engine-dot { animation: none; }
.v-caret { transition: none; }
* { scroll-behavior: auto !important; }
}