fix(design): text on a tint of itself now clears AA app-wide, and the check gates it (#3141)
CI & Build / Plugin hooks (push) Successful in 11s
CI & Build / Python lint (push) Successful in 3s
CI & Build / TypeScript typecheck (push) Successful in 36s
CI & Build / integration (push) Successful in 34s
CI & Build / Python tests (push) Successful in 1m12s
CI & Build / Build & push image (push) Successful in 1m2s
CI & Build / Plugin hooks (push) Successful in 11s
CI & Build / Python lint (push) Successful in 3s
CI & Build / TypeScript typecheck (push) Successful in 36s
CI & Build / integration (push) Successful in 34s
CI & Build / Python tests (push) Successful in 1m12s
CI & Build / Build & push image (push) Successful in 1m2s
The badge fix (#3132) exposed the same defect everywhere: 48 rules painting a token as TEXT on an inline color-mix tint of that same token. Worst raw measurements, across every tint strength in use, both modes, over page/raised/hover: accent 1.53:1 · success 1.67:1 · text-tertiary 2.15:1 warning 2.32:1 · error 2.36:1 against AA's 4.5 THE DEFECT IS IN THE HOUSE, NOT IN SCRIBE. The semantic hues are shared family-wide, and the accent case was measured against every app's real accent, not assumed from Scribe's: Minstrel 1.81, Forge 1.87, Steward 1.65, Roundtable 3.01 — all failing. So the six -fg tokens are recorded on FabledSword (design system 1), where their parents live, rather than copied into each app. 45% toward --fs-text-primary clears AA for ALL FIVE accents (4.56-5.00), so this is one house token rather than five overrides, and it keeps deriving from --fs-accent — an app that overrides its accent still gets a legible tinted-text colour in its own colour, the same mechanism as --fs-accent-soft. The tokens are additive: a sibling app is unaffected until it regenerates its own stylesheet. One token is honestly redundant. --fs-text-secondary already passes at 4.82:1, and --fs-text-secondary-fg barely moves it. It exists so the rule has NO exceptions, because the alternative is a permanent allow-list entry for the one case that happens to pass — and a guard with an invisible exception is a guard that erodes. 46 substitutions across 18 files, each rewriting only the `color:` inside a block that tints its own background. THE CHECK NOW GATES BOTH SPELLINGS. It previously reported the inline form, because a gate nobody can satisfy on the day it lands gets switched off. Both are clean, so both fail the build now. And the check had a false-positive bug worth naming: its `color\s*:` regex matched the tail of `border-color`, `border-left-color` and `outline-color`, so it flagged seven rules that were already correct. A border is a non-text graphic with a 3:1 floor, not text at 4.5. A check that cries wolf on correct code is one that gets muted, so that mattered more than the noise. Verified by construction, not by passing: reintroduced each defect form (exit 1 each), and confirmed a legitimate border-only rule still exits 0. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -206,7 +206,7 @@ router.afterEach(() => {
|
||||
background: var(--fs-accent-soft);
|
||||
}
|
||||
.nav-link.router-link-active {
|
||||
color: var(--fs-accent);
|
||||
color: var(--fs-accent-fg);
|
||||
font-weight: 500;
|
||||
background: color-mix(in srgb, var(--fs-accent) 25%, transparent);
|
||||
box-shadow: 0 0 16px color-mix(in srgb, var(--fs-accent) 30%, transparent);
|
||||
@@ -257,7 +257,7 @@ router.afterEach(() => {
|
||||
font-weight: 500;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
color: var(--fs-accent);
|
||||
color: var(--fs-accent-fg);
|
||||
background: color-mix(in srgb, var(--fs-accent) 15%, transparent);
|
||||
padding: 0.1rem 0.35rem;
|
||||
border-radius: var(--fs-radius-sm);
|
||||
|
||||
@@ -137,12 +137,12 @@ function markerFor(type: DiffLine['type']): string {
|
||||
|
||||
.diff-delete {
|
||||
background: color-mix(in srgb, var(--fs-error) 12%, transparent);
|
||||
color: var(--fs-error);
|
||||
color: var(--fs-error-fg);
|
||||
}
|
||||
|
||||
.diff-insert {
|
||||
background: color-mix(in srgb, var(--fs-success) 12%, transparent);
|
||||
color: var(--fs-success);
|
||||
color: var(--fs-success-fg);
|
||||
}
|
||||
|
||||
.diff-equal {
|
||||
|
||||
@@ -227,11 +227,11 @@ const markers: Record<DiffLine["type"], string> = {
|
||||
.iap-diff-equal { color: var(--fs-text-tertiary); }
|
||||
.iap-diff-delete {
|
||||
background: color-mix(in srgb, var(--fs-error) 10%, transparent);
|
||||
color: var(--fs-error);
|
||||
color: var(--fs-error-fg);
|
||||
}
|
||||
.iap-diff-insert {
|
||||
background: color-mix(in srgb, var(--fs-success) 10%, transparent);
|
||||
color: var(--fs-success);
|
||||
color: var(--fs-success-fg);
|
||||
}
|
||||
|
||||
.iap-diff-marker {
|
||||
|
||||
@@ -156,7 +156,7 @@ const groups = [
|
||||
|
||||
.md-btn.active {
|
||||
background: color-mix(in srgb, var(--fs-accent) 14%, transparent);
|
||||
color: var(--fs-accent);
|
||||
color: var(--fs-accent-fg);
|
||||
box-shadow: 0 0 0 1px color-mix(in srgb, var(--fs-accent) 35%, transparent);
|
||||
}
|
||||
|
||||
|
||||
@@ -679,7 +679,7 @@ async function confirmDelete() {
|
||||
font-weight: 500;
|
||||
background: color-mix(in srgb, var(--fs-accent) 12%, transparent);
|
||||
border: 1px solid color-mix(in srgb, var(--fs-accent) 30%, transparent);
|
||||
color: var(--fs-accent);
|
||||
color: var(--fs-accent-fg);
|
||||
border-radius: 999px;
|
||||
padding: 0.05rem 0.45rem;
|
||||
flex-shrink: 0;
|
||||
@@ -689,7 +689,7 @@ async function confirmDelete() {
|
||||
font-weight: 500;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
color: var(--fs-text-tertiary);
|
||||
color: var(--fs-text-tertiary-fg);
|
||||
background: color-mix(in srgb, var(--fs-text-tertiary) 12%, transparent);
|
||||
border-radius: 999px;
|
||||
padding: 0.05rem 0.45rem;
|
||||
|
||||
@@ -168,7 +168,7 @@ function focusInput() {
|
||||
border-radius: 999px;
|
||||
background: color-mix(in srgb, var(--fs-accent) 15%, transparent);
|
||||
border: 1px solid var(--fs-accent);
|
||||
color: var(--fs-accent);
|
||||
color: var(--fs-accent-fg);
|
||||
font-size: 0.8rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@@ -548,7 +548,7 @@ defineExpose({ reload: loadProjectNotes });
|
||||
|
||||
.note-tag-pill {
|
||||
font-size: 0.58rem;
|
||||
color: var(--fs-accent);
|
||||
color: var(--fs-accent-fg);
|
||||
background: color-mix(in srgb, var(--fs-accent) 10%, transparent);
|
||||
border-radius: 999px;
|
||||
padding: 0 0.3rem;
|
||||
@@ -645,7 +645,7 @@ defineExpose({ reload: loadProjectNotes });
|
||||
.btn-tag-suggestion.applied {
|
||||
background: color-mix(in srgb, var(--fs-accent) 15%, transparent);
|
||||
border-color: var(--fs-accent);
|
||||
color: var(--fs-accent);
|
||||
color: var(--fs-accent-fg);
|
||||
}
|
||||
|
||||
.link-suggest-strip {
|
||||
|
||||
@@ -424,8 +424,8 @@ defineExpose({ reload: loadAll });
|
||||
border-radius: 10px;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
.ms-status-active { background: color-mix(in srgb, var(--fs-accent) 15%, transparent); color: var(--fs-accent); }
|
||||
.ms-status-completed { background: color-mix(in srgb, var(--fs-success) 15%, transparent); color: var(--fs-success); }
|
||||
.ms-status-active { background: color-mix(in srgb, var(--fs-accent) 15%, transparent); color: var(--fs-accent-fg); }
|
||||
.ms-status-completed { background: color-mix(in srgb, var(--fs-success) 15%, transparent); color: var(--fs-success-fg); }
|
||||
|
||||
.task-items {
|
||||
list-style: none;
|
||||
@@ -516,8 +516,8 @@ defineExpose({ reload: loadAll });
|
||||
user-select: none;
|
||||
margin-left: auto;
|
||||
}
|
||||
.status-cycler.status-in_progress { border-color: var(--fs-accent); color: var(--fs-accent); background: color-mix(in srgb, var(--fs-accent) 10%, transparent); }
|
||||
.status-cycler.status-done { border-color: var(--fs-success); color: var(--fs-success); background: color-mix(in srgb, var(--fs-success) 10%, transparent); }
|
||||
.status-cycler.status-in_progress { border-color: var(--fs-accent); color: var(--fs-accent-fg); background: color-mix(in srgb, var(--fs-accent) 10%, transparent); }
|
||||
.status-cycler.status-done { border-color: var(--fs-success); color: var(--fs-success-fg); background: color-mix(in srgb, var(--fs-success) 10%, transparent); }
|
||||
|
||||
.btn-edit-task { margin-left: 0.25rem; }
|
||||
.btn-edit-task:hover { text-decoration: underline; }
|
||||
|
||||
Reference in New Issue
Block a user