fix(tinytorch/ux): site-wide dark-mode coverage for sidebar + inline-fill panels

#1529 fixed dark-mode contrast on preface.qmd by refactoring inline
style="background: #..." panels to .who-card / .callout-note. The
remaining 200+ inline-styled panels across other pages (big-picture,
index, tito/*, datasets, etc.) were still failing in dark mode — the
fix worked for one page but the user-visible experience was patchwork.

Two structural gaps closed:

  1. Sidebar had zero dark-mode coverage. dark-mode.scss declared
     $sidebar-bg-dark = #212529 but never applied it to a selector,
     and shared/styles/partials/_sidebar.scss hardcodes #495057 link
     text against an implicit white surface. Result: white sidebar
     visible on every page in dark mode. Fixed by adding rules for
     #quarto-sidebar, .sidebar-navigation, sidebar items, section
     headers, and dividers — uses the existing $sidebar-bg-dark and
     $border-color-dark variables instead of leaving them dead.

  2. Inline-style panels site-wide. Cataloged the 14 light-fill hex
     values that appear with `background: #X` across the .qmd corpus
     (counts in the SCSS comments) and added a [style*=...] attribute
     selector layer that flips them to #2d2d2d in dark mode, plus the
     8 mid/dark-grey text colors used inline that fail when their
     surface flips. !important is required because inline style= beats
     class specificity. Decorative dark/saturated fills (#263238,
     #0f172a, button blues/oranges, gradient banners) are deliberately
     excluded — they render correctly in both modes.

Plus: thin 1px border on .who-card in dark mode for delineation
against the body bg ($body-bg-dark = #1a1a1a vs card #2d2d2d).

Verified across index, big-picture, and tito/milestones in Playwright
with colorScheme: 'dark' (uses Quarto's prefers-color-scheme initial
toggle path, not just data-bs-theme attribute setting). All measured
contrast ratios >= 11.0 WCAG AA. The defensive layer is a transitional
bridge — long-term, individual pages should be refactored to .who-card
/ .callout-note like preface and tito/milestones already are.
This commit is contained in:
Vijay Janapa Reddi
2026-04-25 08:18:01 -04:00
parent 4c2996e0dc
commit 2707c0546a

View File

@@ -137,3 +137,87 @@ a {
color: #e6e6e6 !important;
p, li, span, div { color: #e6e6e6 !important; }
}
// --- Sidebar dark-mode coverage ---
// shared/styles/partials/_sidebar.scss hardcodes #495057 link text and #2c3e50
// section-header text against an implicit white surface. Without these
// overrides the sidebar stays white in dark mode (visible on every page,
// not just refactored ones).
#quarto-sidebar,
.sidebar.margin-sidebar,
.sidebar-navigation {
background-color: $sidebar-bg-dark;
border-color: $border-color-dark;
}
.sidebar-navigation .sidebar-item a {
color: #cbd5e1; // light slate, readable on $sidebar-bg-dark
}
.sidebar-navigation .sidebar-item a[data-bs-toggle="collapse"] {
color: #e6e6e6; // brighter for section-header hierarchy
}
.sidebar-header,
.sidebar-logo-link + div,
.sidebar-menu-container .text-muted {
color: #a0a0a0;
}
.sidebar-divider {
border-color: $border-color-dark;
}
// --- who-card delineation in dark mode ---
// On #1a1a1a body with #2d2d2d card the contrast is real but subtle; a
// thin border gives the rectangle a clean edge so cards don't blur into
// adjacent prose.
.who-card {
border: 1px solid $border-color-dark;
}
// --- Dark-mode safety net for inline-styled light-fill panels ---
// Several .qmd pages still use inline `style="background: #X..."` for
// callout-style panels (the same failure mode #1529 fixed for preface).
// Until every page is refactored to .who-card / .callout-note, normalize
// the most common light-fill hex values so dark mode is consistent
// site-wide, not patchwork.
//
// !important is required because inline style= beats class specificity.
// The hex list comes from `grep -hoE 'background:\s*#...' tinytorch/quarto/**/*.qmd`
// (occurrence counts in parentheses below). Decorative dark/saturated
// fills (#263238, #0f172a, button blues/oranges) are deliberately excluded
// — those render correctly in both modes.
[style*="background: #fff5f5"], // (27)
[style*="background: #f8f9fa"], // (17)
[style*="background: #e3f2fd"], // (15)
[style*="background: #f3e5f5"], // (9)
[style*="background: #fffbeb"], // (8)
[style*="background: #f0fdf4"], // (5)
[style*="background: #fff3e0"], // (3)
[style*="background: #e8eaf6"], // (3)
[style*="background: #fef3c7"], // (2)
[style*="background: #fdf2f8"], // (1)
[style*="background: #f8fafc"], // (1)
[style*="background: #f0fff4"], // (1)
[style*="background: #e8f5e9"], // (1)
[style*="background: #fafafa"] { // residual from older snippets
background-color: #2d2d2d !important;
border-color: $border-color-dark !important;
}
// Dark/mid-grey text colors used inline assume a light surface; once the
// panel bg flips to #2d2d2d above, these become unreadable. Flip them
// to a slate-light tone that meets WCAG AA on the dark surface.
[style*="color: #64748b"], // (12) slate-500
[style*="color: #6c757d"], // (9) gray-500
[style*="color: #495057"], // (8) gray-700
[style*="color: #37474f"], // (5) blue-grey
[style*="color: #666"], // (4)
[style*="color: #555"], // (4)
[style*="color: #475569"], // (2)
[style*="color: #546e7a"] { // (2)
color: #cbd5e1 !important;
}