Fix Choices.js theme specificity — chain .choices + !important

The b0d3829 overrides lost the cascade battle: the Choices.js CDN CSS
loads AFTER custom.css (inside the modal partial near </body>), so the
CDN's same-specificity rules won by load order. Dropdown still showed
white background + light-grey text in dark mode.

Fix: chain the root `.choices` class to every override (specificity
0,2,0 → 0,3,0) and add !important to color + background + border
properties that Choices.js hardcodes most aggressively. Now the
theme tokens always win regardless of load order.

Visual effect: dropdown option hover state now matches the selected
"Month(s)" button aesthetic (--bg-card-hover subtle lift with
--text-primary text) per Konrad's feedback.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Konrad du Plessis 2026-04-22 23:34:06 +02:00
parent b0d382987b
commit 8ea8955b30

View File

@ -1530,18 +1530,24 @@ body, .card, .modal-content, .form-control, .form-select,
own design tokens so the multi-select picker matches every other card and own design tokens so the multi-select picker matches every other card and
input on the page. All tokens auto-switch between dark (:root) and light input on the page. All tokens auto-switch between dark (:root) and light
(:root.light) themes no duplicate blocks needed. (:root.light) themes no duplicate blocks needed.
Specificity note: the Choices.js CDN CSS loads AFTER custom.css (inside the
modal partial, near </body>). Every rule below chains the root `.choices`
class to beat the CDN's same-class selectors, and uses !important on the
two properties Choices.js hardcodes most aggressively (color + background)
so dark/light theme tokens always win.
*/ */
/* Container — the outer wrapper that replaces the native <select> */ /* Container — the outer wrapper that replaces the native <select> */
.choices { .choices.choices {
margin-bottom: 0; margin-bottom: 0;
} }
/* Closed-state input area (where chips and the placeholder/search sit) */ /* Closed-state input area (where chips and the placeholder/search sit) */
.choices__inner { .choices .choices__inner {
background: var(--bg-inset); background: var(--bg-inset) !important;
color: var(--text-primary); color: var(--text-primary) !important;
border: 1px solid var(--border-default); border: 1px solid var(--border-default) !important;
border-radius: 0.5rem; border-radius: 0.5rem;
padding: 0.4rem 0.55rem; padding: 0.4rem 0.55rem;
min-height: 2.55rem; min-height: 2.55rem;
@ -1549,94 +1555,97 @@ body, .card, .modal-content, .form-control, .form-select,
} }
.choices.is-focused .choices__inner, .choices.is-focused .choices__inner,
.choices.is-open .choices__inner { .choices.is-open .choices__inner {
border-color: var(--accent); border-color: var(--accent) !important;
box-shadow: 0 0 0 0.15rem rgba(232, 133, 26, 0.18); box-shadow: 0 0 0 0.15rem rgba(232, 133, 26, 0.18);
} }
/* The cloned search input typed into when the dropdown is open */ /* The cloned search input typed into when the dropdown is open */
.choices__input { .choices .choices__input {
background: transparent !important; background: transparent !important;
color: var(--text-primary) !important; color: var(--text-primary) !important;
font-size: 0.925rem; font-size: 0.925rem;
} }
.choices__input::placeholder { .choices .choices__input::placeholder {
color: var(--text-tertiary); color: var(--text-tertiary) !important;
} }
/* Dropdown popup — the list of choices */ /* Dropdown popup — the list of choices */
.choices__list--dropdown, .choices .choices__list--dropdown,
.choices__list[aria-expanded] { .choices .choices__list[aria-expanded] {
background: var(--bg-card); background: var(--bg-card) !important;
border: 1px solid var(--border-default); border: 1px solid var(--border-default) !important;
border-radius: 0.5rem; border-radius: 0.5rem;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.28); box-shadow: 0 8px 24px rgba(0, 0, 0, 0.28);
margin-top: 4px; margin-top: 4px;
z-index: 2000; z-index: 2000;
color: var(--text-primary) !important;
} }
/* Individual option rows in the dropdown */ /* Individual option rows in the dropdown — default state */
.choices__list--dropdown .choices__item, .choices .choices__list--dropdown .choices__item,
.choices__list[aria-expanded] .choices__item { .choices .choices__list[aria-expanded] .choices__item {
color: var(--text-primary); color: var(--text-primary) !important;
background: transparent !important;
padding: 0.5rem 0.75rem; padding: 0.5rem 0.75rem;
font-size: 0.9rem; font-size: 0.9rem;
} }
/* Hovered / keyboard-highlighted option */ /* Hovered / keyboard-highlighted option — matches the "Month button selected" look */
.choices__list--dropdown .choices__item--selectable.is-highlighted, .choices .choices__list--dropdown .choices__item--selectable.is-highlighted,
.choices__list[aria-expanded] .choices__item--selectable.is-highlighted { .choices .choices__list[aria-expanded] .choices__item--selectable.is-highlighted {
background: var(--bg-card-hover); background: var(--bg-card-hover) !important;
color: var(--text-primary); color: var(--text-primary) !important;
} }
/* The trailing "Press to select" hint */ /* The trailing "Press to select" hint */
.choices__list--dropdown .choices__item--selectable.is-highlighted::after, .choices .choices__list--dropdown .choices__item--selectable.is-highlighted::after,
.choices__list[aria-expanded] .choices__item--selectable.is-highlighted::after { .choices .choices__list[aria-expanded] .choices__item--selectable.is-highlighted::after {
color: var(--accent); color: var(--accent);
opacity: 0.9; opacity: 0.9;
} }
/* Disabled / placeholder-style rows (e.g. "No matches found") */ /* Disabled / placeholder-style rows (e.g. "No matches found") */
.choices__list--dropdown .choices__item--disabled, .choices .choices__list--dropdown .choices__item--disabled,
.choices__list[aria-expanded] .choices__item--disabled { .choices .choices__list[aria-expanded] .choices__item--disabled {
color: var(--text-tertiary); color: var(--text-tertiary) !important;
} }
/* Placeholder text in the input area when nothing is selected */ /* Placeholder text in the input area when nothing is selected */
.choices__placeholder { .choices .choices__placeholder {
color: var(--text-tertiary); color: var(--text-tertiary) !important;
opacity: 1; opacity: 1;
} }
/* Selected chips in multi-select mode (visible when items are chosen) */ /* Selected chips in multi-select mode (visible when items are chosen) */
.choices__list--multiple .choices__item { .choices .choices__list--multiple .choices__item {
background: var(--accent); background: var(--accent) !important;
border: 1px solid var(--accent); border: 1px solid var(--accent) !important;
color: #fff; color: #fff !important;
font-size: 0.82rem; font-size: 0.82rem;
font-weight: 500; font-weight: 500;
padding: 0.2rem 0.6rem; padding: 0.2rem 0.6rem;
margin: 0.15rem 0.25rem 0.15rem 0; margin: 0.15rem 0.25rem 0.15rem 0;
border-radius: 999px; border-radius: 999px;
} }
.choices__list--multiple .choices__item.is-highlighted { .choices .choices__list--multiple .choices__item.is-highlighted {
background: var(--accent-hover); background: var(--accent-hover) !important;
border-color: var(--accent-hover); border-color: var(--accent-hover) !important;
} }
/* The × button on each selected chip */ /* The × button on each selected chip */
.choices__list--multiple .choices__button { .choices .choices__list--multiple .choices__button {
border-left: 1px solid rgba(255, 255, 255, 0.4); border-left: 1px solid rgba(255, 255, 255, 0.4);
margin: 0 0 0 0.5rem; margin: 0 0 0 0.5rem;
padding-left: 0.5rem; padding-left: 0.5rem;
opacity: 0.85; opacity: 0.85;
} }
.choices__list--multiple .choices__button:hover { .choices .choices__list--multiple .choices__button:hover {
opacity: 1; opacity: 1;
} }
/* No-results / no-choices message */ /* No-results / no-choices message */
.choices__list .choices__item--no-results, .choices .choices__list .choices__item--no-results,
.choices__list .choices__item--no-choices { .choices .choices__list .choices__item--no-choices {
color: var(--text-tertiary); color: var(--text-tertiary) !important;
font-style: italic; font-style: italic;
background: transparent !important;
} }