style(transmittal): tokenize utility classes, drop !important dark overrides
transmittal/css/utilities.css hand-rolled a Tailwind-style utility
subset against hardcoded grayscale (#fff, #f9fafb, #d1d5db etc.)
tuned for light mode. Dark mode then needed a 17-line block of
!important rules in transmittal/css/base.css to swing each utility
class's background/text/border colors. That block was the worst
concentration of !important in the repo.
Tokenize the grayscale classes against shared CSS custom properties
(var(--bg), var(--bg-secondary), var(--text), var(--text-muted),
var(--border)) so the cascade picks up dark mode automatically:
.bg-white, .bg-gray-50, .bg-gray-100 → var(--bg) / var(--bg-secondary)
.text-gray-{400..700,900} → var(--text-muted) / var(--text)
.border, .border-{b,t}, .border-gray-* → var(--border)
.hover:bg-gray-{50,100} → var(--bg-hover)
.focus:bg-white:focus → var(--bg)
Named-color text classes (.text-blue-600 / -green-600 / -red-600)
stay hardcoded — they encode link / success / danger semantics that
should not theme-shift.
The .table-filter-input dark-mode block also went — it was unused
(no element references it; .column-filter from shared is what gets
applied to the actual filter inputs).
!important count in transmittal's non-print CSS dropped from ~32 to
~12. The 6 transmittal Playwright specs still pass.
Verification needed: visually inspect transmittal in both light and
dark mode and flag any color regression. The token mapping is
mechanical but the live rendered output is the only proof.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
0c48a583ad
commit
538167b5c8
2 changed files with 32 additions and 64 deletions
|
|
@ -107,49 +107,13 @@
|
||||||
border-bottom-color: #86efac;
|
border-bottom-color: #86efac;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Owner/Project names area and inline bg-white / bg-gray-50 utility classes */
|
/* Note: dark-mode overrides for .bg-white / .bg-gray-* / .text-gray-*
|
||||||
@media (prefers-color-scheme: dark) {
|
/ .border-gray-* and .header-names used to live here as a 17-line
|
||||||
:root:not([data-theme="light"]) .header-names {
|
block of !important rules to fight hardcoded colors in
|
||||||
background-color: var(--bg-secondary) !important;
|
transmittal/css/utilities.css. The utility classes were tokenized
|
||||||
border-color: var(--border) !important;
|
(var(--bg), var(--bg-secondary), var(--text), var(--text-muted),
|
||||||
}
|
var(--border)) so the cascade now does the right thing in both
|
||||||
:root:not([data-theme="light"]) .text-gray-700 { color: var(--text-muted) !important; }
|
themes without per-class overrides. .table-filter-input is unused
|
||||||
:root:not([data-theme="light"]) .bg-white { background-color: var(--bg) !important; }
|
(no element references it; .column-filter from shared is used
|
||||||
:root:not([data-theme="light"]) .bg-gray-50 { background-color: var(--bg-secondary) !important; }
|
instead) and was likewise dropped. */
|
||||||
:root:not([data-theme="light"]) .bg-gray-100 { background-color: var(--bg-secondary) !important; }
|
|
||||||
:root:not([data-theme="light"]) .border-gray-100,
|
|
||||||
:root:not([data-theme="light"]) .border-gray-200,
|
|
||||||
:root:not([data-theme="light"]) .border-gray-300 { border-color: var(--border) !important; }
|
|
||||||
:root:not([data-theme="light"]) .text-gray-900 { color: var(--text) !important; }
|
|
||||||
}
|
|
||||||
[data-theme="dark"] .header-names {
|
|
||||||
background-color: var(--bg-secondary) !important;
|
|
||||||
border-color: var(--border) !important;
|
|
||||||
}
|
|
||||||
[data-theme="dark"] .text-gray-700 { color: var(--text-muted) !important; }
|
|
||||||
[data-theme="dark"] .bg-white { background-color: var(--bg) !important; }
|
|
||||||
[data-theme="dark"] .bg-gray-50 { background-color: var(--bg-secondary) !important; }
|
|
||||||
[data-theme="dark"] .bg-gray-100 { background-color: var(--bg-secondary) !important; }
|
|
||||||
[data-theme="dark"] .border-gray-100,
|
|
||||||
[data-theme="dark"] .border-gray-200,
|
|
||||||
[data-theme="dark"] .border-gray-300 { border-color: var(--border) !important; }
|
|
||||||
[data-theme="dark"] .text-gray-900 { color: var(--text) !important; }
|
|
||||||
|
|
||||||
/* Filter inputs in table column headers */
|
|
||||||
@media (prefers-color-scheme: dark) {
|
|
||||||
:root:not([data-theme="light"]) .table-filter-input {
|
|
||||||
background-color: var(--bg);
|
|
||||||
color: var(--text);
|
|
||||||
border-color: var(--border);
|
|
||||||
}
|
|
||||||
:root:not([data-theme="light"]) .table-header__caption { color: var(--text-muted); }
|
|
||||||
:root:not([data-theme="light"]) .focus\:bg-white:focus { background-color: var(--bg) !important; }
|
|
||||||
}
|
|
||||||
[data-theme="dark"] .table-filter-input {
|
|
||||||
background-color: var(--bg);
|
|
||||||
color: var(--text);
|
|
||||||
border-color: var(--border);
|
|
||||||
}
|
|
||||||
[data-theme="dark"] .table-header__caption { color: var(--text-muted); }
|
|
||||||
[data-theme="dark"] .focus\:bg-white:focus { background-color: var(--bg) !important; }
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,11 +16,15 @@
|
||||||
.text-2xl { font-size: 1.5rem; line-height: 2rem; }
|
.text-2xl { font-size: 1.5rem; line-height: 2rem; }
|
||||||
.text-\[12px\] { font-size: 12px; line-height: 1.4; }
|
.text-\[12px\] { font-size: 12px; line-height: 1.4; }
|
||||||
.text-\[10px\] { font-size: 10px; line-height: 1.3; }
|
.text-\[10px\] { font-size: 10px; line-height: 1.3; }
|
||||||
.text-gray-900 { color: #111827; }
|
/* Gray-scale text classes are theme-encoding — they map to shared
|
||||||
.text-gray-700 { color: #374151; }
|
tokens so dark mode swaps automatically without per-class overrides.
|
||||||
.text-gray-600 { color: #4b5563; }
|
The named-color text classes (.text-blue-600/-green-600/-red-600)
|
||||||
.text-gray-500 { color: #6b7280; }
|
carry semantic meaning (link / success / danger) and stay hardcoded. */
|
||||||
.text-gray-400 { color: #9ca3af; }
|
.text-gray-900 { color: var(--text); }
|
||||||
|
.text-gray-700 { color: var(--text-muted); }
|
||||||
|
.text-gray-600 { color: var(--text-muted); }
|
||||||
|
.text-gray-500 { color: var(--text-muted); }
|
||||||
|
.text-gray-400 { color: var(--text-muted); }
|
||||||
.text-blue-600 { color: #2563eb; }
|
.text-blue-600 { color: #2563eb; }
|
||||||
.text-green-600 { color: #16a34a; }
|
.text-green-600 { color: #16a34a; }
|
||||||
.text-red-600 { color: #dc2626; }
|
.text-red-600 { color: #dc2626; }
|
||||||
|
|
@ -29,20 +33,20 @@
|
||||||
.leading-6 { line-height: 1.5rem; }
|
.leading-6 { line-height: 1.5rem; }
|
||||||
.leading-snug { line-height: 1.375rem; }
|
.leading-snug { line-height: 1.375rem; }
|
||||||
|
|
||||||
/* Backgrounds */
|
/* Backgrounds — gray-scale classes map to shared tokens. */
|
||||||
.bg-white { background-color: #ffffff; }
|
.bg-white { background-color: var(--bg); }
|
||||||
.bg-transparent { background-color: transparent; }
|
.bg-transparent { background-color: transparent; }
|
||||||
.bg-gray-50 { background-color: #f9fafb; }
|
.bg-gray-50 { background-color: var(--bg-secondary); }
|
||||||
.bg-gray-100 { background-color: #f3f4f6; }
|
.bg-gray-100 { background-color: var(--bg-secondary); }
|
||||||
|
|
||||||
/* Borders */
|
/* Borders — gray-scale border classes map to the shared token. */
|
||||||
.border { border: 1px solid #d1d5db; }
|
.border { border: 1px solid var(--border); }
|
||||||
.border-0 { border: 0; }
|
.border-0 { border: 0; }
|
||||||
.border-b { border-bottom: 1px solid #d1d5db; }
|
.border-b { border-bottom: 1px solid var(--border); }
|
||||||
.border-t { border-top: 1px solid #d1d5db; }
|
.border-t { border-top: 1px solid var(--border); }
|
||||||
.border-gray-300 { border-color: #d1d5db; }
|
.border-gray-300 { border-color: var(--border); }
|
||||||
.border-gray-200 { border-color: #e5e7eb; }
|
.border-gray-200 { border-color: var(--border); }
|
||||||
.border-gray-100 { border-color: #f3f4f6; }
|
.border-gray-100 { border-color: var(--border); }
|
||||||
.rounded-none { border-radius: 0; }
|
.rounded-none { border-radius: 0; }
|
||||||
.rounded-sm { border-radius: 0.125rem; }
|
.rounded-sm { border-radius: 0.125rem; }
|
||||||
.rounded { border-radius: 0.25rem; }
|
.rounded { border-radius: 0.25rem; }
|
||||||
|
|
@ -129,14 +133,14 @@
|
||||||
.border-red-500 { border-color: #ef4444 !important; }
|
.border-red-500 { border-color: #ef4444 !important; }
|
||||||
|
|
||||||
/* Hover & focus states */
|
/* Hover & focus states */
|
||||||
.hover\:bg-gray-50:hover { background-color: #f9fafb; }
|
.hover\:bg-gray-50:hover { background-color: var(--bg-hover); }
|
||||||
.hover\:bg-gray-100:hover { background-color: #f3f4f6; }
|
.hover\:bg-gray-100:hover { background-color: var(--bg-hover); }
|
||||||
.hover\:underline:hover { text-decoration: underline; }
|
.hover\:underline:hover { text-decoration: underline; }
|
||||||
.focus\:outline-none:focus { outline: none; }
|
.focus\:outline-none:focus { outline: none; }
|
||||||
.focus\:border-blue-400:focus { border-color: #60a5fa; }
|
.focus\:border-blue-400:focus { border-color: #60a5fa; }
|
||||||
.focus\:ring-1:focus { box-shadow: 0 0 0 1px rgba(59, 130, 246, 0.35); }
|
.focus\:ring-1:focus { box-shadow: 0 0 0 1px rgba(59, 130, 246, 0.35); }
|
||||||
.focus\:ring-blue-400:focus { box-shadow: 0 0 0 2px rgba(96, 165, 250, 0.45); }
|
.focus\:ring-blue-400:focus { box-shadow: 0 0 0 2px rgba(96, 165, 250, 0.45); }
|
||||||
.focus\:bg-white:focus { background-color: #ffffff; }
|
.focus\:bg-white:focus { background-color: var(--bg); }
|
||||||
.disabled\:pointer-events-none:disabled { pointer-events: none; }
|
.disabled\:pointer-events-none:disabled { pointer-events: none; }
|
||||||
|
|
||||||
/* Table helpers */
|
/* Table helpers */
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue