Spaces:
Running
Running
| /* ═══════════════════════════════════════════════════════════════════════ | |
| LEGIBILITY (2026-08-01) — units, the run strip, and the decision trace. | |
| All of it lives here rather than in app.css for the reason PR #14 kept the | |
| catalog out: app.css is ~8,600 lines with a hostile cascade, and three | |
| people are editing this tree at once. Everything below is either a NEW | |
| class or a deliberate, commented override of an app.css rule; nothing | |
| redefines a token. | |
| Colours are app.css tokens only (--line, --line-strong, --ink, | |
| --ink-strong, --ink-soft, --ink-faint, --bg-card, --bg-subtle, --bg-app, | |
| --danger, --success, --font-mono, --r-2..--r-4, --elev-4, --topbar-h). | |
| Inventing a var() name here would compute the whole shorthand to nothing | |
| — see ENGINEERING.md §13.1. | |
| ═══════════════════════════════════════════════════════════════════════ */ | |
| /* ── 1. UNITS ───────────────────────────────────────────────────────────── | |
| "Fitness 1.0" had its unit in a hover title only, so for anyone who did | |
| not hover the right 60px it did not exist. These carry it in the page. */ | |
| /* The unit chip inside a column header. Subordinate to the header word but | |
| not hidden — it has to survive being read at a glance. */ | |
| .th-unit { | |
| font-family: var(--font-mono); | |
| font-size: 9.5px; | |
| letter-spacing: 0.02em; | |
| font-weight: 400; | |
| color: var(--ink-faint); | |
| /* The header cell is .num (right-aligned) and already tight; keep the | |
| chip on the same baseline rather than wrapping it to its own line. */ | |
| white-space: nowrap; | |
| } | |
| /* The always-visible legend that answers "what does 1.0 represent?" without | |
| opening the collapsed "How to read this" block. */ | |
| .unit-legend { | |
| margin: 0 0 10px; | |
| padding: 8px 11px; | |
| border-left: 2px solid var(--line-strong); | |
| background: var(--bg-subtle); | |
| border-radius: 0 var(--r-2) var(--r-2) 0; | |
| font-size: 12px; | |
| line-height: 1.55; | |
| color: var(--ink-soft); | |
| } | |
| .unit-legend strong { color: var(--ink-strong); font-weight: 600; } | |
| .unit-legend em { font-style: italic; } | |
| .unit-legend--tight { margin: 6px 0 10px; font-size: 11.5px; } | |
| /* Inline unit after a score, in the Radar rows and the round-2 learned rows. | |
| Mono so it reads as a unit rather than as part of the number. */ | |
| .rs-unit, | |
| .ls-unit { | |
| font-family: var(--font-mono); | |
| font-size: 9.5px; | |
| color: var(--ink-faint); | |
| letter-spacing: 0.02em; | |
| } | |
| /* ── 2. THE CHAT-LIBRARY CAP ────────────────────────────────────────────── | |
| The reviewer typed 30 into "Variants to generate" and a Turing-run library | |
| came back with 10 rows. The only disclosure was a banner in a different | |
| section of the page. This one sits under the input itself. */ | |
| .setting-note { | |
| margin: 6px 0 0; | |
| font-size: 11px; | |
| line-height: 1.5; | |
| color: var(--ink-faint); | |
| } | |
| .setting-note strong { color: var(--ink-soft); font-weight: 600; } | |
| /* Requested-vs-delivered, stated on the result itself. Not an error state — | |
| a chat run capping at 20 is correct behaviour, it just has to be said. */ | |
| .count-note { | |
| display: block; | |
| margin-top: 4px; | |
| font-family: var(--font-mono); | |
| font-size: 10.5px; | |
| letter-spacing: 0.02em; | |
| color: var(--ink-faint); | |
| } | |
| .count-note b { color: var(--ink-soft); font-weight: 600; } | |
| /* ── 3. INTERACTION RADAR PROGRESS ──────────────────────────────────────── | |
| One ESM-2 forward pass per variant, serial, with no signal at all beyond a | |
| button reading "Analyzing…". Tool rows in the rail have had an elapsed | |
| clock since the CRISPR index made two minutes of silence read as a hang; | |
| this path never used it. */ | |
| .radar-elapsed { | |
| font-family: var(--font-mono); | |
| font-size: 10.5px; | |
| letter-spacing: 0.03em; | |
| color: var(--ink-faint); | |
| font-variant-numeric: tabular-nums; /* so the seconds don't jitter */ | |
| } | |
| .radar-progress { | |
| display: block; | |
| height: 2px; | |
| margin-top: 7px; | |
| background: var(--line); | |
| overflow: hidden; | |
| border-radius: 1px; | |
| } | |
| /* Indeterminate on purpose. The server returns one response for the whole | |
| library, so there is no honest per-variant fraction to draw — a bar that | |
| filled to 60% would be inventing progress. This says "working", and the | |
| elapsed clock next to it says how long for. */ | |
| .radar-progress::after { | |
| content: ""; | |
| display: block; | |
| width: 34%; | |
| height: 100%; | |
| background: var(--ink-soft); | |
| animation: tdRadarSlide 1.25s var(--ease-snap) infinite; | |
| } | |
| @keyframes tdRadarSlide { | |
| 0% { transform: translateX(-100%); } | |
| 100% { transform: translateX(320%); } | |
| } | |
| @media (prefers-reduced-motion: reduce) { | |
| .radar-progress::after { animation: none; width: 100%; opacity: 0.35; } | |
| } | |
| /* ── 4. THE RUN STRIP (was the unlabelled "context 0% · $0.11") ─────────── | |
| Two numbers with no nouns read as noise. They are kept — cost is exactly | |
| what someone deciding whether to keep going wants — but named, given a | |
| denominator so a sub-1% reading isn't rendered as a flat "0%", and given | |
| the trace as somewhere to go and read what they mean in full sentences. */ | |
| /* The bar was flex:1 and ate the row; the text now carries the meaning, so | |
| the bar becomes a fixed-width glance indicator. Specificity (0,2,0) beats | |
| app.css's (0,1,0) `.cp-meter-bar`, and this file loads after it — both | |
| conditions are needed (ENGINEERING.md §13.2/§13.3). */ | |
| .cp-meter .cp-meter-bar { flex: 0 0 28px; } | |
| /* Wraps rather than truncates. Measured at 390px (the rail's real width): | |
| "Context 41k / 1M (4%) · $0.14 model cost" overflows by 7px, and an | |
| ellipsis there eats "model cost" — putting the label back out of reach on | |
| exactly the narrow screens this change set exists to serve. A second line | |
| costs 12px; a hidden noun costs the whole fix. */ | |
| .cp-meter .cp-meter-t { | |
| flex: 1 1 auto; | |
| min-width: 0; | |
| white-space: normal; | |
| line-height: 1.35; | |
| font-variant-numeric: tabular-nums; | |
| } | |
| /* The way into the trace. Text, not a glyph: the whole complaint upstream of | |
| this file is unlabelled controls. */ | |
| .cp-trace-btn { | |
| flex: 0 0 auto; | |
| font-family: var(--font-mono); | |
| font-size: 9.5px; | |
| letter-spacing: 0.06em; | |
| text-transform: uppercase; | |
| padding: 3px 8px; | |
| border: 1px solid var(--line-strong); | |
| border-radius: 999px; | |
| background: transparent; | |
| color: var(--ink-soft); | |
| cursor: pointer; | |
| white-space: nowrap; | |
| } | |
| .cp-trace-btn:hover { border-color: var(--ink-soft); color: var(--ink-strong); } | |
| .cp-trace-btn[hidden] { display: none; } | |
| /* Matches .cp-icon's rule: the 57px collapsed rail has room for nothing. */ | |
| body[data-cockpit="min"] .cp-trace-btn { display: none; } | |
| /* ── 5. THE DECISION TRACE ──────────────────────────────────────────────── | |
| The rail already showed every step; it showed them as a river. Ten minutes | |
| in, "what did it actually do and why" is unanswerable because the answer | |
| scrolled past. This is the same events, held still. */ | |
| .td-trace { | |
| position: fixed; | |
| inset: 0; | |
| z-index: 60; /* above the rail (z 40s) and the canvas */ | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| padding: 24px; | |
| } | |
| .td-trace[hidden] { display: none; } | |
| .td-trace-scrim { | |
| position: absolute; | |
| inset: 0; | |
| background: rgba(10, 10, 10, 0.42); | |
| border: 0; | |
| padding: 0; | |
| cursor: pointer; | |
| } | |
| .td-trace-panel { | |
| position: relative; | |
| display: flex; | |
| flex-direction: column; | |
| width: min(760px, 100%); | |
| max-height: min(82vh, 900px); | |
| background: var(--bg-card); | |
| border: 1px solid var(--line-strong); | |
| border-radius: var(--r-4); | |
| box-shadow: var(--elev-4); | |
| overflow: hidden; | |
| } | |
| .td-trace-head { | |
| display: flex; | |
| align-items: flex-start; | |
| gap: 12px; | |
| padding: 16px 18px 12px; | |
| border-bottom: 1px solid var(--line); | |
| flex: 0 0 auto; | |
| } | |
| .td-trace-head h2 { | |
| margin: 0; | |
| font-size: 15px; | |
| letter-spacing: -0.01em; | |
| color: var(--ink-strong); | |
| } | |
| .td-trace-sub { | |
| margin: 4px 0 0; | |
| font-size: 12px; | |
| line-height: 1.5; | |
| color: var(--ink-faint); | |
| } | |
| .td-trace-x { | |
| margin-left: auto; | |
| flex: 0 0 auto; | |
| width: 26px; | |
| height: 26px; | |
| line-height: 1; | |
| font-size: 15px; | |
| border: 1px solid var(--line-strong); | |
| border-radius: var(--r-2); | |
| background: transparent; | |
| color: var(--ink-soft); | |
| cursor: pointer; | |
| } | |
| .td-trace-x:hover { border-color: var(--ink-soft); color: var(--ink-strong); } | |
| /* Goal + the two meters, spelled out in words. This is where "context 3%" | |
| is allowed the room to say what it is. */ | |
| .td-trace-meta { | |
| flex: 0 0 auto; | |
| padding: 12px 18px; | |
| border-bottom: 1px solid var(--line); | |
| background: var(--bg-subtle); | |
| font-size: 12px; | |
| line-height: 1.6; | |
| color: var(--ink-soft); | |
| } | |
| .td-trace-goal { | |
| margin: 0 0 8px; | |
| color: var(--ink-strong); | |
| font-size: 13px; | |
| } | |
| .td-trace-goal b { | |
| display: block; | |
| font-family: var(--font-mono); | |
| font-size: 9px; | |
| letter-spacing: 0.1em; | |
| text-transform: uppercase; | |
| color: var(--ink-faint); | |
| font-weight: 500; | |
| margin-bottom: 2px; | |
| } | |
| .td-trace-facts { margin: 0; padding: 0; list-style: none; } | |
| .td-trace-facts li { margin: 0; } | |
| .td-trace-facts b { color: var(--ink-strong); font-weight: 600; } | |
| .td-trace-list { | |
| flex: 1 1 auto; | |
| min-height: 0; | |
| overflow-y: auto; | |
| margin: 0; | |
| padding: 0; | |
| list-style: none; | |
| -webkit-overflow-scrolling: touch; | |
| } | |
| .td-step { border-bottom: 1px solid var(--line); } | |
| .td-step:last-child { border-bottom: 0; } | |
| .td-step > details > summary { | |
| display: flex; | |
| align-items: baseline; | |
| gap: 10px; | |
| padding: 10px 18px; | |
| cursor: pointer; | |
| list-style: none; | |
| } | |
| .td-step > details > summary::-webkit-details-marker { display: none; } | |
| .td-step > details > summary:hover { background: var(--bg-subtle); } | |
| .td-step > details[open] > summary { background: var(--bg-subtle); } | |
| .td-step-n { | |
| flex: 0 0 auto; | |
| min-width: 20px; | |
| font-family: var(--font-mono); | |
| font-size: 10px; | |
| color: var(--ink-faint); | |
| font-variant-numeric: tabular-nums; | |
| } | |
| .td-step-main { flex: 1 1 auto; min-width: 0; } | |
| .td-step-obj { | |
| display: block; | |
| font-size: 13px; | |
| color: var(--ink-strong); | |
| overflow-wrap: break-word; | |
| } | |
| .td-step-args { | |
| display: block; | |
| margin-top: 1px; | |
| font-family: var(--font-mono); | |
| font-size: 10.5px; | |
| color: var(--ink-faint); | |
| overflow-wrap: break-word; | |
| } | |
| .td-step-status { | |
| flex: 0 0 auto; | |
| font-family: var(--font-mono); | |
| font-size: 9px; | |
| letter-spacing: 0.08em; | |
| text-transform: uppercase; | |
| padding: 2px 7px; | |
| border-radius: 999px; | |
| border: 1px solid var(--line-strong); | |
| color: var(--ink-faint); | |
| } | |
| .td-step--ok .td-step-status { color: var(--success); border-color: var(--success); } | |
| .td-step--fail .td-step-status { color: var(--danger); border-color: var(--danger); } | |
| .td-step--run .td-step-status { color: var(--ink-soft); } | |
| .td-step-t { | |
| flex: 0 0 auto; | |
| font-family: var(--font-mono); | |
| font-size: 10px; | |
| color: var(--ink-faint); | |
| font-variant-numeric: tabular-nums; | |
| min-width: 34px; | |
| text-align: right; | |
| } | |
| .td-step-detail { | |
| padding: 2px 18px 14px 48px; | |
| font-size: 12.5px; | |
| line-height: 1.6; | |
| color: var(--ink); | |
| } | |
| .td-step-lbl { | |
| margin: 10px 0 2px; | |
| font-family: var(--font-mono); | |
| font-size: 9px; | |
| letter-spacing: 0.1em; | |
| text-transform: uppercase; | |
| color: var(--ink-faint); | |
| } | |
| .td-step-detail p { margin: 0; overflow-wrap: break-word; } | |
| .td-step-detail p.td-muted { color: var(--ink-faint); font-style: italic; } | |
| .td-step-kv { | |
| margin: 0; | |
| display: grid; | |
| grid-template-columns: minmax(0, auto) minmax(0, 1fr); | |
| gap: 1px 12px; | |
| font-family: var(--font-mono); | |
| font-size: 11px; | |
| } | |
| .td-step-kv dt { color: var(--ink-faint); } | |
| .td-step-kv dd { margin: 0; color: var(--ink-strong); overflow-wrap: anywhere; } | |
| /* Plan steps replayed inside a "Plan" entry. */ | |
| .td-plan { margin: 0; padding: 0; list-style: none; font-size: 12.5px; } | |
| .td-plan li { display: flex; gap: 8px; align-items: baseline; } | |
| .td-plan-g { flex: 0 0 auto; width: 12px; color: var(--ink-faint); font-family: var(--font-mono); font-size: 11px; } | |
| .td-plan--done > span:last-child { color: var(--ink-faint); } | |
| .td-trace-empty { | |
| margin: 0; | |
| padding: 28px 18px; | |
| text-align: center; | |
| font-size: 12.5px; | |
| color: var(--ink-faint); | |
| } | |
| .td-trace-empty[hidden] { display: none; } | |
| .td-trace-foot { | |
| flex: 0 0 auto; | |
| padding: 10px 18px; | |
| border-top: 1px solid var(--line); | |
| font-size: 11px; | |
| line-height: 1.5; | |
| color: var(--ink-faint); | |
| } | |
| /* The rail is ~390px and phones are narrower still; a 24px inset frame there | |
| wastes a third of the screen. Full-bleed sheet instead. */ | |
| @media (max-width: 720px) { | |
| .td-trace { padding: 0; align-items: stretch; } | |
| .td-trace-panel { | |
| width: 100%; | |
| max-height: none; | |
| height: 100%; | |
| border: 0; | |
| border-radius: 0; | |
| } | |
| .td-step-detail { padding-left: 18px; } | |
| } | |