fix: MPS-24 — systemic dark-mode token sweep (close the whole bug class)
After fixing the same dark-mode bug 4x one surface at a time, swept it system-wide. Root pattern: var(--name, fallback) where --name is NOT a token in tokens.css -> the light fallback applied in BOTH themes -> dark broken. Offenders: --color-surface*, --color-border*, --color-text*, --text-color, --surface* (none are tokens). - Remapped all 53 occurrences in common.css to the real theme-aware tokens (--surface-base/-dim/-container, --border-default, --text-primary/-body/-muted), KEEPING each fallback literal (comma-boundary sed). Diff verified: exactly 53/53 var-name-only swaps, no fallback/structure change, line count unchanged. - Light mode: identical where token==fallback (#fff, off-whites); minor canonical nudges where they differ (muted #888->#666, body #333->#515151, primary #111->#333, borders ->#e0e0e0) — the design system's intended values, the 'light looks better' direction. - Dark mode fixed app-wide (wells, suggest cards, counts, checksum table, and every other surface using these vars). - Excluded (not the bug): --shop-theme-*, --color-accent, --pico-*, --primary-color, the --dark-* family, theme-neutral font/size vars. - CLAUDE.md: DARK-MODE TRAP rule + pre-commit grep gate. mps-24.md Phase 2.8r. 1151 passed (CSS-only).
This commit is contained in:
parent
b39efcad4e
commit
64bc435a00
3 changed files with 79 additions and 53 deletions
|
|
@ -290,6 +290,11 @@ Note: `align-items`, `justify-items`, `align-content`, `justify-content`, `place
|
|||
|
||||
**DESIGN TOKENS**: All new styles must consume tokens from `tokens.css` — never hardcode colors, spacing, radii, shadows, or font sizes. Use `var(--token-name)` or `var(--token-name, fallback)`. Our token scale uses a 4px spacing base and major third (1.250) type scale.
|
||||
|
||||
**DARK-MODE TRAP — only reference vars that are REAL tokens.** A `var(--name, fallback)` where `--name` is **not** defined in `tokens.css` silently uses the light `fallback` in BOTH themes → looks fine in light, broken (light card / invisible text) in dark. This bit us repeatedly (wells, suggest cards, checksum table). The offenders were ad-hoc names like `--color-surface*`, `--color-border*`, `--color-text*`, `--text-color`, `--surface*` — none are tokens. **Use the real theme-aware tokens**: surfaces → `--surface-base` / `--surface-dim` / `--surface-container`; borders → `--border-light` / `--border-default` / `--border-color`; text → `--text-primary` / `--text-body` / `--text-muted` (all carry `:root` + `[data-theme="dark"]` values). Pre-commit grep gate (must be empty):
|
||||
```
|
||||
grep -oE 'var\(\s*--(color-(surface|border|text)[a-z0-9-]*|surface(-[a-z]+)?|text-color)\s*,' make_post_sell/static/css/common.css
|
||||
```
|
||||
|
||||
**STYLEGUIDE**: When creating new UI components (buttons, wells, alerts, layout patterns, etc.), add a live example to `/styleguide` (`make_post_sell/templates/styleguide.j2`). Our styleguide is our single source of truth for our component library. If it's not in our styleguide, it doesn't exist as a pattern.
|
||||
|
||||
**CSS MEDIA SIZING**: Never combine `width: 100%` with `max-height` on media elements (img, video). `width: 100%` forces our element to span our full container even when `max-height` constrains our rendered content, creating dead whitespace. Use `width: auto` + `max-width: 100%` + `max-height` instead — our element shrinks to match our actual content aspect ratio within both constraints.
|
||||
|
|
|
|||
|
|
@ -363,6 +363,27 @@ Tests (`test_functional.py::TestProductTagsSpa`):
|
|||
Deferred (occasional click, not the hot path): AJAX-ifying the
|
||||
"Suggest categories" link — still a full navigation by design.
|
||||
|
||||
**Phase 2.8r — systemic dark-mode token sweep** (shipped 2026-05-18):
|
||||
after fixing the same dark-mode bug 4× one-surface-at-a-time (wells,
|
||||
suggest cards, counts, checksum table) the operator asked for a
|
||||
systemic pass. Root pattern: CSS referenced `var(--name, fallback)`
|
||||
where `--name` is **not** a token in `tokens.css` (`--color-surface*`,
|
||||
`--color-border*`, `--color-text*`, `--text-color`, `--surface*`), so
|
||||
the light `fallback` applied in BOTH themes → dark broken. Swept all
|
||||
53 occurrences in `common.css` to the real theme-aware tokens
|
||||
(`--surface-base/-dim/-container`, `--border-default`,
|
||||
`--text-primary/-body/-muted`), **keeping each fallback literal**
|
||||
(comma-boundary sed; verified diff is exactly 53/53 var-name-only
|
||||
swaps, no fallback/structure change, line count unchanged). Light
|
||||
mode now uses canonical token values: identical where token==fallback
|
||||
(`#fff`, off-whites); minor design-consistent nudges where they
|
||||
differ (muted `#888→#666`, body `#333→#515151`, primary `#111→#333`,
|
||||
borders → `#e0e0e0`). Dark mode fixed app-wide. Excluded (not the
|
||||
bug / runtime-defined): `--shop-theme-*`, `--color-accent`,
|
||||
`--pico-*`, `--primary-color`, the `--dark-*` family (dark fallbacks,
|
||||
dark-only rules), and theme-neutral font/size/radius vars. CLAUDE.md
|
||||
gains a "DARK-MODE TRAP" rule + pre-commit grep gate.
|
||||
|
||||
**Phase 2.8q — click-to-copy hashes + styled checksum table** (shipped
|
||||
2026-05-18): operator: make the checksum hashes click-to-copy (they
|
||||
were unstyled, overflowing the column). New reusable
|
||||
|
|
|
|||
|
|
@ -1482,18 +1482,18 @@ a.tag-chip {
|
|||
display: inline-grid;
|
||||
place-items: center;
|
||||
padding: var(--space-1, 4px) var(--space-3, 12px);
|
||||
border: 1px solid var(--color-border, #d1d5db);
|
||||
border: 1px solid var(--border-default, #d1d5db);
|
||||
border-radius: var(--radius-pill, 999px);
|
||||
background: var(--color-surface, #fff);
|
||||
color: var(--color-text, #111);
|
||||
background: var(--surface-base, #fff);
|
||||
color: var(--text-primary, #111);
|
||||
font-size: var(--type-body-sm-size, 0.875rem);
|
||||
text-decoration: none;
|
||||
transition: background-color 150ms ease, border-color 150ms ease;
|
||||
}
|
||||
|
||||
a.tag-chip:hover {
|
||||
background: var(--color-surface-2, #f3f4f6);
|
||||
border-color: var(--color-border-strong, #9ca3af);
|
||||
background: var(--surface-container, #f3f4f6);
|
||||
border-color: var(--border-default, #9ca3af);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
|
|
@ -1545,10 +1545,10 @@ li.tag-chip-removable {
|
|||
gap: var(--space-2, 8px);
|
||||
margin: 0 var(--space-2, 8px) var(--space-2, 8px) 0;
|
||||
padding: var(--space-1, 4px) var(--space-2, 8px) var(--space-1, 4px) var(--space-3, 12px);
|
||||
border: 1px solid var(--color-border, #d1d5db);
|
||||
border: 1px solid var(--border-default, #d1d5db);
|
||||
border-radius: var(--radius-pill, 999px);
|
||||
background: var(--color-surface, #fff);
|
||||
color: var(--color-text, #111);
|
||||
background: var(--surface-base, #fff);
|
||||
color: var(--text-primary, #111);
|
||||
font-size: var(--type-body-sm-size, 0.875rem);
|
||||
}
|
||||
|
||||
|
|
@ -1566,7 +1566,7 @@ button.tag-chip-removable-x {
|
|||
border: none;
|
||||
border-radius: var(--radius-pill, 999px);
|
||||
background: transparent;
|
||||
color: var(--color-text-muted, #6b7280);
|
||||
color: var(--text-muted, #6b7280);
|
||||
font-size: var(--type-body-size, 1rem);
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
|
|
@ -1639,8 +1639,8 @@ form.serp-sort-form select {
|
|||
padding: var(--space-1, 4px) var(--space-2, 8px);
|
||||
border-radius: var(--radius-sm, 4px);
|
||||
border: 1px solid var(--border-color, #dee2e6);
|
||||
background: var(--surface-color, #fff);
|
||||
color: var(--text-color, #222);
|
||||
background: var(--surface-base, #fff);
|
||||
color: var(--text-body, #222);
|
||||
font-size: var(--type-body-sm-size, 0.875rem);
|
||||
}
|
||||
@media (max-width: 600px) {
|
||||
|
|
@ -1719,7 +1719,7 @@ p.serp-list-price a {
|
|||
}
|
||||
p.serp-list-excerpt {
|
||||
margin: 0;
|
||||
color: var(--text-color, #333);
|
||||
color: var(--text-body, #333);
|
||||
font-size: var(--type-body-sm-size, 0.875rem);
|
||||
line-height: 1.5;
|
||||
/* No max-width — the excerpt fills the row body so the layout uses
|
||||
|
|
@ -1870,7 +1870,7 @@ li.tag-list-item {
|
|||
align-items: center;
|
||||
gap: var(--space-3, 12px);
|
||||
padding: var(--space-2, 8px);
|
||||
border: 1px solid var(--color-border, #e5e7eb);
|
||||
border: 1px solid var(--border-default, #e5e7eb);
|
||||
border-radius: var(--radius-sm, 4px);
|
||||
}
|
||||
li.tag-list-item.tag-list-drop-target {
|
||||
|
|
@ -1995,9 +1995,9 @@ div.tag-flash {
|
|||
div.tag-flash-toast {
|
||||
padding: var(--space-2, 8px) var(--space-3, 12px);
|
||||
border-radius: var(--radius-sm, 4px);
|
||||
border: 1px solid var(--color-border, #d1d5db);
|
||||
background: var(--color-surface-2, #f9fafb);
|
||||
color: var(--color-text, #111);
|
||||
border: 1px solid var(--border-default, #d1d5db);
|
||||
background: var(--surface-container, #f9fafb);
|
||||
color: var(--text-primary, #111);
|
||||
transition: opacity 400ms ease;
|
||||
}
|
||||
|
||||
|
|
@ -2090,7 +2090,7 @@ li.serp-rail-card {
|
|||
padding: var(--space-2, 8px);
|
||||
border: 1px solid var(--border-color, #e5e7eb);
|
||||
border-radius: var(--radius-sm, 4px);
|
||||
background: var(--surface, #fff);
|
||||
background: var(--surface-base, #fff);
|
||||
}
|
||||
a.serp-rail-thumb-link {
|
||||
display: block;
|
||||
|
|
@ -2134,14 +2134,14 @@ span.serp-rail-card-price {
|
|||
details.facet-details {
|
||||
margin: var(--space-3, 12px) 0;
|
||||
padding: var(--space-3, 12px);
|
||||
background: var(--surface, #fff);
|
||||
background: var(--surface-base, #fff);
|
||||
border: 1px solid var(--border-color, #e5e7eb);
|
||||
border-radius: var(--radius-md, 8px);
|
||||
}
|
||||
details.facet-details summary.facet-details-summary {
|
||||
cursor: pointer;
|
||||
font-weight: 600;
|
||||
color: var(--text-color, #333);
|
||||
color: var(--text-body, #333);
|
||||
padding: var(--space-1, 4px) 0;
|
||||
}
|
||||
span.facet-details-active-mark {
|
||||
|
|
@ -2182,7 +2182,7 @@ h2.facet-title {
|
|||
margin: 0;
|
||||
font-size: var(--type-body-size, 1rem);
|
||||
font-weight: 600;
|
||||
color: var(--text-color, #333);
|
||||
color: var(--text-body, #333);
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
select.facet-select {
|
||||
|
|
@ -2190,8 +2190,8 @@ select.facet-select {
|
|||
padding: var(--space-2, 8px);
|
||||
border: 1px solid var(--border-color, #d1d5db);
|
||||
border-radius: var(--radius-sm, 4px);
|
||||
background: var(--surface, #fff);
|
||||
color: var(--text-color, #333);
|
||||
background: var(--surface-base, #fff);
|
||||
color: var(--text-body, #333);
|
||||
}
|
||||
div.facet-price-range {
|
||||
display: grid;
|
||||
|
|
@ -2211,8 +2211,8 @@ input.facet-price-input {
|
|||
padding: var(--space-2, 8px);
|
||||
border: 1px solid var(--border-color, #d1d5db);
|
||||
border-radius: var(--radius-sm, 4px);
|
||||
background: var(--surface, #fff);
|
||||
color: var(--text-color, #333);
|
||||
background: var(--surface-base, #fff);
|
||||
color: var(--text-body, #333);
|
||||
min-width: 0;
|
||||
}
|
||||
a.facet-clear-link {
|
||||
|
|
@ -2240,7 +2240,7 @@ a.facet-tag {
|
|||
gap: var(--space-2, 8px);
|
||||
padding: var(--space-2, 8px) var(--space-3, 12px);
|
||||
border-radius: var(--radius-sm, 4px);
|
||||
color: var(--text-color, #333);
|
||||
color: var(--text-body, #333);
|
||||
text-decoration: none;
|
||||
transition: background-color 150ms ease;
|
||||
word-break: break-word;
|
||||
|
|
@ -2318,7 +2318,7 @@ div.edit-page > section.well2 > form > h3:first-child {
|
|||
|
||||
/* Pricing-mode fieldset on edit page — improved spacing. */
|
||||
div.edit-page fieldset {
|
||||
border: 1px solid var(--color-border, #ddd);
|
||||
border: 1px solid var(--border-default, #ddd);
|
||||
border-radius: var(--radius-md, 8px);
|
||||
padding: var(--space-3, 12px) var(--space-4, 16px);
|
||||
margin: var(--space-3, 12px) 0;
|
||||
|
|
@ -2327,7 +2327,7 @@ div.edit-page fieldset {
|
|||
div.edit-page fieldset legend {
|
||||
padding: 0 var(--space-2, 8px);
|
||||
font-weight: 600;
|
||||
color: var(--color-text-muted, #666);
|
||||
color: var(--text-muted, #666);
|
||||
}
|
||||
|
||||
div.edit-page fieldset label[style*="display:block"],
|
||||
|
|
@ -2346,7 +2346,7 @@ div.edit-page > section.product-title-and-description {
|
|||
Used in the upload/preview/thumbnail blocks of the edit page. */
|
||||
.file-meta {
|
||||
margin: var(--space-1, 4px) 0;
|
||||
color: var(--color-text-muted, #666);
|
||||
color: var(--text-muted, #666);
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
|
|
@ -2356,7 +2356,7 @@ div.edit-page > section.product-title-and-description {
|
|||
|
||||
.file-meta-item + .file-meta-item::before {
|
||||
content: " · ";
|
||||
color: var(--color-text-muted, #aaa);
|
||||
color: var(--text-muted, #aaa);
|
||||
margin: 0 var(--space-1, 4px);
|
||||
}
|
||||
|
||||
|
|
@ -2371,13 +2371,13 @@ div.edit-page > section.product-title-and-description {
|
|||
font-size: 0.95rem;
|
||||
font-weight: 600;
|
||||
margin: 0 0 var(--space-2, 8px);
|
||||
color: var(--color-text-primary, #333);
|
||||
color: var(--text-primary, #333);
|
||||
}
|
||||
|
||||
/* Form helper text — small tag below labels that doesn't break layout. */
|
||||
.form-help {
|
||||
display: block;
|
||||
color: var(--color-text-muted, #666);
|
||||
color: var(--text-muted, #666);
|
||||
font-size: 0.85em;
|
||||
margin: var(--space-1, 4px) 0 var(--space-2, 8px);
|
||||
}
|
||||
|
|
@ -2423,8 +2423,8 @@ div.edit-page > section.well2 > form > h3:first-child {
|
|||
gap: var(--space-3, 12px);
|
||||
margin-bottom: var(--space-3, 12px);
|
||||
padding-bottom: var(--space-3, 12px);
|
||||
border-bottom: 1px solid var(--color-border, #eee);
|
||||
color: var(--color-text-primary, #222);
|
||||
border-bottom: 1px solid var(--border-default, #eee);
|
||||
color: var(--text-primary, #222);
|
||||
}
|
||||
|
||||
.edit-card-icon {
|
||||
|
|
@ -2452,7 +2452,7 @@ div.edit-page > section.well2 > form > h3:first-child {
|
|||
.edit-permanent-link {
|
||||
text-align: right;
|
||||
margin: 0;
|
||||
color: var(--color-text-muted, #666);
|
||||
color: var(--text-muted, #666);
|
||||
font-size: 0.85em;
|
||||
}
|
||||
|
||||
|
|
@ -2467,7 +2467,7 @@ div.edit-page > section.well2 > form > h3:first-child {
|
|||
border-radius: var(--radius-pill, 999px);
|
||||
font-size: 0.85em;
|
||||
font-weight: 600;
|
||||
background: var(--color-text-muted, #888);
|
||||
background: var(--text-muted, #888);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
|
|
@ -2485,7 +2485,7 @@ div.edit-page > section.well2 > form > h3:first-child {
|
|||
}
|
||||
|
||||
.edit-status-pill-private {
|
||||
background: var(--color-text-muted, #888);
|
||||
background: var(--text-muted, #888);
|
||||
}
|
||||
|
||||
.edit-status-pill-unlisted {
|
||||
|
|
@ -2535,10 +2535,10 @@ div.edit-page button.mps-submit-primary:disabled,
|
|||
bottom: var(--space-3, 12px);
|
||||
margin-top: var(--space-5, 20px);
|
||||
padding: var(--space-3, 12px) var(--space-4, 16px);
|
||||
background: var(--surface, #fff);
|
||||
background: var(--surface-base, #fff);
|
||||
border-radius: var(--radius-md, 8px);
|
||||
box-shadow: var(--elevation-3, 0 4px 12px rgba(0,0,0,0.07));
|
||||
border: 1px solid var(--color-border, #eee);
|
||||
border: 1px solid var(--border-default, #eee);
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto;
|
||||
align-items: center;
|
||||
|
|
@ -2547,7 +2547,7 @@ div.edit-page button.mps-submit-primary:disabled,
|
|||
}
|
||||
|
||||
.edit-save-bar-status {
|
||||
color: var(--color-text-muted, #666);
|
||||
color: var(--text-muted, #666);
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
|
|
@ -2841,7 +2841,7 @@ section.upload-product-and-preview {
|
|||
|
||||
.upload-thumbnails-hint {
|
||||
margin: 0;
|
||||
color: var(--color-text-muted, #666);
|
||||
color: var(--text-muted, #666);
|
||||
text-align: right;
|
||||
max-width: 320px;
|
||||
}
|
||||
|
|
@ -2864,7 +2864,7 @@ section.upload-product-and-preview {
|
|||
gap: var(--space-2, 8px);
|
||||
padding: var(--space-3, 12px);
|
||||
background: var(--surface-dim, #f9f9fa);
|
||||
border: 1px solid var(--color-border, #eee);
|
||||
border: 1px solid var(--border-default, #eee);
|
||||
border-radius: var(--radius-md, 8px);
|
||||
min-width: 0;
|
||||
}
|
||||
|
|
@ -2874,7 +2874,7 @@ section.upload-product-and-preview {
|
|||
max-width: 100%;
|
||||
height: 140px;
|
||||
object-fit: contain;
|
||||
background: var(--surface, #fff);
|
||||
background: var(--surface-base, #fff);
|
||||
border-radius: var(--radius-sm, 4px);
|
||||
}
|
||||
|
||||
|
|
@ -5611,14 +5611,14 @@ textarea {
|
|||
padding: 10px 14px;
|
||||
align-items: center;
|
||||
text-align: left;
|
||||
background: var(--surface-secondary, #f6f8fa);
|
||||
background: var(--surface-dim, #f6f8fa);
|
||||
border: 1px solid var(--border-color, #dee2e6);
|
||||
border-radius: var(--radius-md, 8px);
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .watch-countdown {
|
||||
background: var(--surface-secondary, #161b22);
|
||||
background: var(--surface-dim, #161b22);
|
||||
border-color: var(--border-color, #7ab9ff);
|
||||
}
|
||||
|
||||
|
|
@ -5884,8 +5884,8 @@ textarea {
|
|||
padding: var(--space-1, 4px) var(--space-2, 8px);
|
||||
border-radius: var(--radius-sm, 4px);
|
||||
border: 1px solid var(--border-color, #dee2e6);
|
||||
background: var(--surface-color, #fff);
|
||||
color: var(--text-color, #222);
|
||||
background: var(--surface-base, #fff);
|
||||
color: var(--text-body, #222);
|
||||
font-size: var(--font-size-sm, 0.875rem);
|
||||
}
|
||||
|
||||
|
|
@ -6387,7 +6387,7 @@ html[data-color-filter="7"] {
|
|||
padding: var(--space-2, 8px);
|
||||
border: 1px solid var(--border-default, #ccc);
|
||||
border-radius: var(--radius-sm, 4px);
|
||||
background: var(--surface-default, #fff);
|
||||
background: var(--surface-base, #fff);
|
||||
color: var(--text-primary, #333);
|
||||
}
|
||||
|
||||
|
|
@ -6443,7 +6443,7 @@ html[data-color-filter="7"] {
|
|||
}
|
||||
|
||||
.auction-stat-label {
|
||||
color: var(--color-text-muted, #888);
|
||||
color: var(--text-muted, #888);
|
||||
font-size: 0.85em;
|
||||
}
|
||||
|
||||
|
|
@ -6466,10 +6466,10 @@ html[data-color-filter="7"] {
|
|||
font-weight: bold;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
background: var(--color-text-muted, #888);
|
||||
background: var(--text-muted, #888);
|
||||
}
|
||||
|
||||
.auction-state-0 { background: var(--color-text-muted, #888); } /* Draft */
|
||||
.auction-state-0 { background: var(--text-muted, #888); } /* Draft */
|
||||
.auction-state-1 { background: var(--color-info, #17a2b8); } /* Scheduled */
|
||||
.auction-state-2 { background: var(--color-success, #28a745); } /* Active */
|
||||
.auction-state-3 { background: var(--color-warning, #ffc107); color: #333; } /* Ended */
|
||||
|
|
@ -6480,8 +6480,8 @@ html[data-color-filter="7"] {
|
|||
.offer-state-1 { background: var(--color-success, #28a745); } /* Accepted */
|
||||
.offer-state-2 { background: var(--color-primary, #5871ad); } /* Countered */
|
||||
.offer-state-3 { background: var(--color-error, #dc3545); } /* Declined */
|
||||
.offer-state-4 { background: var(--color-text-muted, #888); } /* Expired */
|
||||
.offer-state-5 { background: var(--color-text-muted, #888); } /* Withdrawn */
|
||||
.offer-state-4 { background: var(--text-muted, #888); } /* Expired */
|
||||
.offer-state-5 { background: var(--text-muted, #888); } /* Withdrawn */
|
||||
.offer-state-6 { background: var(--color-success, #28a745); } /* Paid */
|
||||
|
||||
.auction-flash {
|
||||
|
|
@ -6511,7 +6511,7 @@ html[data-color-filter="7"] {
|
|||
|
||||
.offer-event {
|
||||
padding: var(--space-2) 0;
|
||||
border-bottom: 1px solid var(--color-border, #eee);
|
||||
border-bottom: 1px solid var(--border-default, #eee);
|
||||
}
|
||||
|
||||
.offer-event:last-child {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue