refactor(frontend): derive the sweep-row visual language into sweep-shared.css (#3207)
CI & Build / Python lint (push) Successful in 2s
CI & Build / Plugin hooks (push) Successful in 12s
CI & Build / integration (push) Successful in 52s
CI & Build / TypeScript typecheck (push) Successful in 53s
CI & Build / Python tests (push) Successful in 1m32s
CI & Build / Build & push image (push) Failing after 22s

The note sweep, rule sweep, preference drift and rule history panes each
restated the same row recipe in a scoped block. It now lives once in
assets/sweep-shared.css under `sweep-` names (unprefixed globals would
leak into the unrelated scoped .row-title/.lede/.age/.actions elsewhere),
imported unscoped beside each pane's own scoped remainder.

Moved only what was shared: RuleHistoryPanel takes .sweep-state and keeps
its button row head; PreferenceDrift keeps its tiny-type footnote and
overrides the action row's layout. Lede and state now use the body-sm
token instead of 0.85rem/0.9rem (13px vs 13.6/14.4px) — one value, from
the design system.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-24 06:45:43 -04:00
co-authored by Claude Opus 5.5
parent 952e56ee75
commit 22b7a928da
5 changed files with 193 additions and 178 deletions
+134
View File
@@ -0,0 +1,134 @@
/* The sweep-row visual language (#3207).
*
* A "sweep" is a pane that lists records in the order they most need a human
* — the note verification sweep, the rule sweep, preference drift — as one
* raised row per record: an italic title that opens it, an age or date pushed
* right, a small grid of facts, and a row of plain buttons. It was written
* out four times, scoped, before this sheet existed.
*
* Imported UNSCOPED (`<style src="@/assets/sweep-shared.css" />`), so every
* class is prefixed `sweep-`: `.row-title`, `.lede`, `.age` and `.actions`
* also exist, scoped, in views that have nothing to do with sweeps, and an
* unprefixed global would leak into all of them. What a pane does
* differently stays in its own scoped block — spacing remainders, a `code`
* style — rather than growing a modifier here per pane.
*/
.sweep-lede {
margin: 0;
max-width: 62ch;
font-size: var(--fs-size-body-sm);
color: var(--fs-text-secondary);
line-height: var(--fs-leading-body);
}
.sweep-filters {
display: flex;
gap: var(--fs-space-5);
align-items: center;
flex-wrap: wrap;
}
.sweep-filter {
display: flex;
align-items: center;
gap: var(--fs-space-2);
font-size: 0.82rem;
color: var(--fs-text-secondary);
}
.sweep-filter input[type="checkbox"] { accent-color: var(--fs-accent); }
.sweep-state {
margin: 0;
font-size: var(--fs-size-body-sm);
color: var(--fs-text-secondary);
}
.sweep-state.empty { color: var(--fs-text-tertiary); }
.sweep-rows {
list-style: none;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
gap: var(--fs-space-3);
}
.sweep-row {
background: var(--fs-surface-raised);
border-radius: var(--fs-radius-md);
padding: var(--fs-space-3);
}
.sweep-row-head {
display: flex;
align-items: baseline;
gap: var(--fs-space-2);
flex-wrap: wrap;
}
.sweep-row-title {
background: none;
border: none;
padding: 0;
cursor: pointer;
font-family: Fraunces, serif;
font-style: italic;
font-size: 1.02rem;
color: var(--fs-text-primary);
text-align: left;
}
.sweep-row-title:hover { text-decoration: underline; }
/* The ORDER carries urgency — the top of a sweep is the thing that most needs
a look. No red/amber ramp: it would restate the ordering and force an
invented "stale after N days" threshold. "Never" is marked because it is
categorically DIFFERENT from a date, not a worse one. */
.sweep-age {
margin-left: auto;
font-size: 0.78rem;
color: var(--fs-text-secondary);
font-variant-numeric: tabular-nums;
}
.sweep-age.unchecked { font-style: italic; color: var(--fs-text-tertiary); }
.sweep-check {
display: grid;
grid-template-columns: auto 1fr;
gap: 0.15rem var(--fs-space-3);
margin: var(--fs-space-3) 0 0;
}
.sweep-check dt {
font-size: 0.7rem;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--fs-text-tertiary);
}
.sweep-check dd {
margin: 0;
font-size: 0.82rem;
color: var(--fs-text-primary);
min-width: 0;
}
.sweep-actions {
display: flex;
gap: var(--fs-space-2);
margin-top: var(--fs-space-3);
}
.sweep-actions button {
cursor: pointer;
font: inherit;
font-size: 0.78rem;
background: var(--fs-surface-page);
color: var(--fs-text-primary);
border: 1px solid var(--fs-border-color);
border-radius: var(--fs-radius-md);
padding: 0.25rem 0.6rem;
}
.sweep-actions button:hover:not(:disabled) { background: var(--fs-surface-hover); }
.sweep-actions button:disabled { opacity: var(--fs-disabled-opacity); cursor: default; }
.sweep-footnote {
margin: 0;
max-width: 62ch;
font-size: 0.78rem;
color: var(--fs-text-tertiary);
line-height: 1.45;
}