PluginProbe
Darkify – Dark Mode & Night Mode for Website & Admin (Dark Theme Included) / 2.1.3
Darkify – Dark Mode & Night Mode for Website & Admin (Dark Theme Included) v2.1.3
2.1.3 2.1.2 2.1.1 2.1.0 2.0.4 2.0.3 2.0.2 2.0.1 2.0.0 1.5.5 1.5.4 1.5.3 1.5.2 1.5.1 1.5.0 trunk 1.0.1 1.1.0 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.3.0 All 57 releases
← All changes | src/assets/css/client_main.css +582 -73 1.3.0 → 2.1.3 View file →
@@ -1,4 +1,22 @@
1 +/*
2 + * The colour rules below set `background-color`, never the `background`
3 + * shorthand — and that distinction is load-bearing, not a style preference.
4 + *
5 + * `background` resets every background property it does not mention, so a rule
6 + * of the form `background: <colour> !important` does not just repaint an
7 + * element: it sets `background-image: none` on it. Everything a design paints
8 + * through that property disappears — a select's dropdown chevron, an icon on a
9 + * button, a sprite, a texture, a pattern, a gradient. And because the rule is
10 + * `!important`, it outranks even an inline `background-image`, so nothing the
11 + * engine writes inline can put the image back.
12 + *
13 + * The pairing was invisible while every rule also declared `background-color`
14 + * on the next line with the same value: the shorthand contributed nothing to
15 + * the colour and only did the damage. Dropping it changes no colour anywhere
16 + * and lets the design's own imagery survive into dark mode.
17 + */
18 +
1 19 .darkify_dark_mode_enabled
2 20 .darkify_style_all:not(
3 21 .darkify_switch,
4 22 .darkify_switch *,
@@ -4,12 +22,14 @@
4 22 .darkify_switch *,
5 23 .darkify_ignore,
6 24 .darkify_ignore *
7 25 ) {
8 - background: var(--darkify_dark_mode_bg) !important;
9 26 background-color: var(--darkify_dark_mode_bg) !important;
10 27 color: var(--darkify_dark_mode_text_color) !important;
11 - border-color: var(--darkify_dark_mode_border_color) !important;
28 + border-right-color: var(--darkify_dark_mode_border_color) !important;
29 + border-left-color: var(--darkify_dark_mode_border_color) !important;
30 + border-top-color: var(--darkify_dark_mode_border_color) !important;
31 + border-bottom-color: var(--darkify_dark_mode_border_color) !important;
12 32 }
13 33 .darkify_dark_mode_enabled
14 34 .darkify_style_bg_txt:not(
15 35 .darkify_switch,
@@ -16,9 +36,8 @@
16 36 .darkify_switch *,
17 37 .darkify_ignore,
18 38 .darkify_ignore *
19 39 ) {
20 - background: var(--darkify_dark_mode_bg) !important;
21 40 background-color: var(--darkify_dark_mode_bg) !important;
22 41 color: var(--darkify_dark_mode_text_color) !important;
23 42 }
24 43 .darkify_dark_mode_enabled
@@ -27,11 +46,13 @@
27 46 .darkify_switch *,
28 47 .darkify_ignore,
29 48 .darkify_ignore *
30 49 ) {
31 - background: var(--darkify_dark_mode_bg) !important;
32 50 background-color: var(--darkify_dark_mode_bg) !important;
33 - border-color: var(--darkify_dark_mode_border_color) !important;
51 + border-right-color: var(--darkify_dark_mode_border_color) !important;
52 + border-left-color: var(--darkify_dark_mode_border_color) !important;
53 + border-top-color: var(--darkify_dark_mode_border_color) !important;
54 + border-bottom-color: var(--darkify_dark_mode_border_color) !important;
34 55 }
35 56 .darkify_dark_mode_enabled
36 57 .darkify_style_txt_border:not(
37 58 .darkify_switch,
@@ -39,9 +60,12 @@
39 60 .darkify_ignore,
40 61 .darkify_ignore *
41 62 ) {
42 63 color: var(--darkify_dark_mode_text_color) !important;
43 - border-color: var(--darkify_dark_mode_border_color) !important;
64 + border-right-color: var(--darkify_dark_mode_border_color) !important;
65 + border-left-color: var(--darkify_dark_mode_border_color) !important;
66 + border-top-color: var(--darkify_dark_mode_border_color) !important;
67 + border-bottom-color: var(--darkify_dark_mode_border_color) !important;
44 68 }
45 69 .darkify_dark_mode_enabled
46 70 .darkify_style_bg:not(
47 71 .darkify_switch,
@@ -48,9 +72,8 @@
48 72 .darkify_switch *,
49 73 .darkify_ignore,
50 74 .darkify_ignore *
51 75 ) {
52 - background: var(--darkify_dark_mode_bg) !important;
53 76 background-color: var(--darkify_dark_mode_bg) !important;
54 77 }
55 78 .darkify_dark_mode_enabled
56 79 .darkify_style_txt:not(
@@ -67,9 +90,12 @@
67 90 .darkify_switch *,
68 91 .darkify_ignore,
69 92 .darkify_ignore *
70 93 ) {
71 - border-color: var(--darkify_dark_mode_border_color) !important;
94 + border-right-color: var(--darkify_dark_mode_border_color) !important;
95 + border-left-color: var(--darkify_dark_mode_border_color) !important;
96 + border-top-color: var(--darkify_dark_mode_border_color) !important;
97 + border-bottom-color: var(--darkify_dark_mode_border_color) !important;
72 98 }
73 99 .darkify_dark_mode_enabled
74 100 .darkify_style_secondary_bg:not(
75 101 .darkify_switch,
@@ -76,9 +102,8 @@
76 102 .darkify_switch *,
77 103 .darkify_ignore,
78 104 .darkify_ignore *
79 105 ) {
80 - background: var(--darkify_dark_mode_secondary_bg) !important;
81 106 background-color: var(--darkify_dark_mode_secondary_bg) !important;
82 107 }
83 108
84 109 /*Handle Link Style*/
@@ -101,8 +126,58 @@
101 126 ):hover {
102 127 color: var(--darkify_dark_mode_link_hover_color) !important;
103 128 }
104 129
130 +/*
131 + * Colour overrides ("Replace Individual Colors").
132 + *
133 + * The value arrives as a custom property set inline by
134 + * darkify_process_color_overrides(); these rules are what actually apply it.
135 + * It used to be written straight onto the property as an inline `!important`,
136 + * which outranks every author rule in the cascade — so an overridden element
137 + * could never show its dark-mode `:hover` colour. Moving the application into
138 + * the stylesheet puts it back into normal specificity competition.
139 + *
140 + * The selector shape is deliberate, load-bearing, and measured against the
141 + * rules it has to sit between:
142 + *
143 + * .darkify_dark_mode_enabled .darkify_style_x:not(...) = (0,3,0)
144 + * .darkify_dark_mode_enabled .darkify_style_link:not(...) = (0,3,3)
145 + * ^ higher than its siblings because its :not() list carries
146 + * `.darkify-nav ul li a`, and :not() takes the specificity of its most
147 + * specific argument — three type selectors' worth.
148 + * .darkify_dark_mode_enabled .darkify_style_x:not(...):hover = (0,4,0)
149 + *
150 + * So the override must be ABOVE (0,3,3) and BELOW (0,4,0): that means exactly
151 + * three classes and at least four types. The repeated class buys the classes;
152 + * `html:is(html):is(html):is(html)` buys the types without changing what the
153 + * selector matches, since :is() takes its argument's specificity and every
154 + * argument here is the element the rule already starts from.
155 + *
156 + * Do NOT add a `:not()` or another class — a fourth class ties the hover rules
157 + * on class count and the override starts winning hover again, which is the
158 + * exact bug this replaced. Elements inside `.darkify_switch` /
159 + * `.darkify_ignore` are never processed, so they never carry these classes.
160 + */
161 +html:is(html):is(html):is(html).darkify_dark_mode_enabled .darkify_ovr_bg.darkify_ovr_bg {
162 + background-color: var(--darkify-ovr-bg) !important;
163 +}
164 +html:is(html):is(html):is(html).darkify_dark_mode_enabled .darkify_ovr_color.darkify_ovr_color {
165 + color: var(--darkify-ovr-color) !important;
166 +}
167 +html:is(html):is(html):is(html).darkify_dark_mode_enabled .darkify_ovr_bt.darkify_ovr_bt {
168 + border-top-color: var(--darkify-ovr-bt) !important;
169 +}
170 +html:is(html):is(html):is(html).darkify_dark_mode_enabled .darkify_ovr_br.darkify_ovr_br {
171 + border-right-color: var(--darkify-ovr-br) !important;
172 +}
173 +html:is(html):is(html):is(html).darkify_dark_mode_enabled .darkify_ovr_bb.darkify_ovr_bb {
174 + border-bottom-color: var(--darkify-ovr-bb) !important;
175 +}
176 +html:is(html):is(html):is(html).darkify_dark_mode_enabled .darkify_ovr_bl.darkify_ovr_bl {
177 + border-left-color: var(--darkify-ovr-bl) !important;
178 +}
179 +
105 180 /*Handle Form Element Style*/
106 181 .darkify_dark_mode_enabled
107 182 .darkify_style_form_element:not(
108 183 .darkify_switch,
@@ -109,9 +184,8 @@
109 184 .darkify_switch *,
110 185 .darkify_ignore,
111 186 .darkify_ignore *
112 187 ) {
113 - background: var(--darkify_dark_mode_input_bg) !important;
114 188 background-color: var(--darkify_dark_mode_input_bg) !important;
115 189 color: var(--darkify_dark_mode_input_text_color) !important;
116 190 }
117 191 .darkify_dark_mode_enabled
@@ -131,14 +205,160 @@
131 205 .darkify_switch *,
132 206 .darkify_ignore,
133 207 .darkify_ignore *
134 208 ) {
135 - background: var(--darkify_dark_mode_btn_bg) !important;
136 209 background-color: var(--darkify_dark_mode_btn_bg) !important;
137 210 color: var(--darkify_dark_mode_btn_text_color) !important;
211 + /*
212 + * Buttons carry their own border token rather than the page's.
213 + *
214 + * The classifier takes `darkify_style_all` off an element the moment it calls
215 + * it a button, so until these four lines existed a button's border was the
216 + * one colour on the page dark mode never touched: an outline button kept the
217 + * light design's brand edge — a teal ring around a grey fill — and no setting
218 + * could reach it. A button also cannot simply borrow the generic border
219 + * colour, because its border belongs to the button's own colour set: it is
220 + * usually the fill or a shade of it, which is why the default for these
221 + * tokens mirrors the button background.
222 + */
223 + border-right-color: var(--darkify_dark_mode_btn_border_color) !important;
224 + border-left-color: var(--darkify_dark_mode_btn_border_color) !important;
225 + border-top-color: var(--darkify_dark_mode_btn_border_color) !important;
226 + border-bottom-color: var(--darkify_dark_mode_btn_border_color) !important;
138 227 }
228 +/* the hover state */
229 +.darkify_dark_mode_enabled
230 + .darkify_style_button:not(
231 + .darkify_switch,
232 + .darkify_switch *,
233 + .darkify_ignore,
234 + .darkify_ignore *
235 + ):hover {
236 + background-color: var(--darkify_dark_mode_btn_hover_bg) !important;
237 + color: var(--darkify_dark_mode_btn_text_hover_color) !important;
238 + border-right-color: var(--darkify_dark_mode_btn_hover_border_color) !important;
239 + border-left-color: var(--darkify_dark_mode_btn_hover_border_color) !important;
240 + border-top-color: var(--darkify_dark_mode_btn_hover_border_color) !important;
241 + border-bottom-color: var(--darkify_dark_mode_btn_hover_border_color) !important;
242 +}
139 243
244 +
140 245 /* ========================
246 + Borders the design does not draw
247 +===========================*/
248 +/*
249 + * A side marked here had a width in the light design but no colour — the
250 + * `border: 8px solid transparent` idiom themes and block grids use for gutters
251 + * and alignment. It occupies space and paints nothing.
252 + *
253 + * The rules above cannot tell those sides apart from real ones: they set all
254 + * four border colours at once, because a class cannot carry per-side
255 + * information. Painting a gutter turns invisible spacing into a visible line,
256 + * and an element ringed by four of them grows a box that the light design never
257 + * had — the effect that made WooCommerce product cards appear boxed in dark
258 + * mode while looking open in light.
259 + *
260 + * The classifier stamps these markers on exactly the sides it measured as
261 + * transparent, so each one is pinned back to transparent regardless of which
262 + * colour rule matched. They repeat the `:not(...)` shape of the rules they
263 + * override so the specificity matches, and sit after them so they win the tie.
264 + */
265 +.darkify_dark_mode_enabled
266 + .darkify_border_keep_top:not(
267 + .darkify_switch,
268 + .darkify_switch *,
269 + .darkify_ignore,
270 + .darkify_ignore *
271 + ) {
272 + border-top-color: transparent !important;
273 +}
274 +.darkify_dark_mode_enabled
275 + .darkify_border_keep_right:not(
276 + .darkify_switch,
277 + .darkify_switch *,
278 + .darkify_ignore,
279 + .darkify_ignore *
280 + ) {
281 + border-right-color: transparent !important;
282 +}
283 +.darkify_dark_mode_enabled
284 + .darkify_border_keep_bottom:not(
285 + .darkify_switch,
286 + .darkify_switch *,
287 + .darkify_ignore,
288 + .darkify_ignore *
289 + ) {
290 + border-bottom-color: transparent !important;
291 +}
292 +.darkify_dark_mode_enabled
293 + .darkify_border_keep_left:not(
294 + .darkify_switch,
295 + .darkify_switch *,
296 + .darkify_ignore,
297 + .darkify_ignore *
298 + ) {
299 + border-left-color: transparent !important;
300 +}
301 +
302 +/* ========================
303 + Pre-paint baseline (FOUC)
304 +===========================*/
305 +/*
306 + * Dark mode is decided in the <head>, but the colours come from a DOM walk that
307 + * cannot start until the DOM exists. Something has to cover that gap.
308 + *
309 + * It cannot be a colour wash on the elements themselves. The engine derives
310 + * each dark colour by *reading* the element's computed light colour, so any
311 + * rule that restyles elements beforehand destroys its input — everything reads
312 + * back as the wash and nothing can be derived.
313 + *
314 + * A `brightness()` filter on <html> used to fill the gap. It painted only, so
315 + * `getComputedStyle` still reported the design's real colours, but it dimmed
316 + * the *whole viewport* — on a slow page that reads as a grey overlay sitting
317 + * over the site for the entire load, and it repeats on every navigation. The
318 + * filter is gone for that reason.
319 + *
320 + * What is left is the page backdrop alone: the root paints the configured dark
321 + * background from the first frame, so the gap before the walk is a dark page
322 + * rather than a white one. Content that has already painted keeps its light
323 + * colours for those few frames — a much smaller artefact than dimming the
324 + * entire viewport.
325 + *
326 + * Deliberately temporary: the class comes off the moment the first walk has
327 + * assigned real colours.
328 + */
329 +html.darkify_dark_mode_enabled.darkify_prepaint {
330 + background-color: var(--darkify_dark_mode_bg) !important;
331 +}
332 +
333 +/*
334 + * The gap the backdrop above cannot cover.
335 + *
336 + * `html`'s dark background is only visible while nothing paints over it, and
337 + * on essentially every theme `body` carries its own opaque light background,
338 + * which does. So the intent of the rule above — "the gap before the walk is a
339 + * dark page rather than a white one" — was defeated in practice: reloading with
340 + * dark mode on showed the site's full light design for as long as the walk took,
341 + * then flipped. That flip is the flicker.
342 + *
343 + * It cannot be fixed by washing the elements: the engine derives every dark
344 + * colour by reading the element's computed light colour, so a colour applied
345 + * beforehand becomes the input and the derivation collapses. `visibility` is
346 + * the one property that hides the artefact without being read — it does not
347 + * change any computed colour, and unlike `display` it keeps layout, so the walk
348 + * measures exactly what it would have measured anyway.
349 + *
350 + * Scoped to its own class rather than `darkify_prepaint` so it can be dropped
351 + * the instant the first walk has assigned colours, which is earlier than the
352 + * backdrop is dropped. The inline script in the page head clears it on a
353 + * failsafe timer regardless, so a failed or missing engine can never leave the
354 + * page hidden.
355 + */
356 +html.darkify_dark_mode_enabled.darkify_fouc_guard body {
357 + visibility: hidden !important;
358 +}
359 +
360 +/* ========================
141 361 Admin Bar Menu Design
142 362 ===========================*/
143 363 .darkify_admin_bar_switch_container {
144 364 cursor: pointer !important;
@@ -147,18 +367,25 @@
147 367 justify-content: center;
148 368 width: 40px !important;
149 369 height: 32px !important;
150 370 }
371 +/* On Darkify's own settings/help screens the admin-bar node is always rendered
372 + so the React admin can reveal it the instant "Admin Panel Dark Mode" is
373 + switched on (see WpAdminBarBridge) rather than only after a reload. It starts
374 + hidden whenever the option is off. */
375 +.darkify_admin_bar_switch_container.darkify_admin_bar_hidden {
376 + display: none !important;
377 +}
151 378 .darkify_admin_bar_switch_container .ab-item {
152 379 height: 18px !important;
153 380 cursor: pointer !important;
154 381 background-color: #ffffff !important;
155 - -webkit-mask: url(../img/switch_icons/switch_apple_light.svg) no-repeat center;
156 - mask: url(../img/switch_icons/switch_apple_light.svg) no-repeat center;
382 + -webkit-mask: url(../../Admin/assets/images/switch_apple_light.svg) no-repeat center;
383 + mask: url(../../Admin/assets/images/switch_apple_light.svg) no-repeat center;
157 384 }
158 385 .darkify_dark_mode_enabled .darkify_admin_bar_switch_container .ab-item {
159 - -webkit-mask: url(../img/switch_icons/switch_apple_dark.svg) no-repeat center;
160 - mask: url(../img/switch_icons/switch_apple_dark.svg) no-repeat center;
386 + -webkit-mask: url(../../Admin/assets/images/switch_apple_dark.svg) no-repeat center;
387 + mask: url(../../Admin/assets/images/switch_apple_dark.svg) no-repeat center;
161 388 }
162 389
163 390 /* ========================
164 391 Block Editor Menu Design
@@ -172,8 +399,9 @@
172 399 border: 0;
173 400 background: #121116;
174 401 border-radius: 3px;
175 402 padding: 0 12px;
403 + margin-right: 8px;
176 404 }
177 405 .darkify_dark_mode_enabled .darkify_block_editor_switch {
178 406 background: #ffffff;
179 407 }
@@ -180,34 +408,22 @@
180 408 .darkify_block_editor_switch .icon {
181 409 width: 20px;
182 410 height: 20px;
183 411 background-color: #ffffff !important;
412 + -webkit-mask: url(../../Admin/assets/images/switch_apple_light.svg) no-repeat center;
413 + mask: url(../../Admin/assets/images/switch_apple_light.svg) no-repeat center;
184 414 }
185 415
416 +.darkify_dark_mode_enabled .darkify_block_editor_switch .icon {
417 + background-color: #171717 !important;
418 + -webkit-mask: url(../../Admin/assets/images/switch_apple_dark.svg) no-repeat center;
419 + mask: url(../../Admin/assets/images/switch_apple_dark.svg) no-repeat center;
420 +}
421 +
186 422 /* ========================
187 423 Switch Design
188 424 ===========================*/
189 425
190 -.darkify_switch {
191 - --darkify_switch_position_from_top_right_top: 40px;
192 - --darkify_switch_position_from_top_right_right: 40px;
193 - --darkify_switch_position_from_bottom_right_bottom: 40px;
194 - --darkify_switch_position_from_bottom_right_right: 40px;
195 - --darkify_switch_position_from_top_left_top: 40px;
196 - --darkify_switch_position_from_top_left_left: 40px;
197 - --darkify_switch_position_from_bottom_left_bottom: 40px;
198 - --darkify_switch_position_from_bottom_left_left: 40px;
199 - --darkify_switch_position_from_top_right_top_in_mobile: 40px;
200 - --darkify_switch_position_from_top_right_right_in_mobile: 40px;
201 - --darkify_switch_position_from_bottom_right_bottom_in_mobile: 40px;
202 - --darkify_switch_position_from_bottom_right_right_in_mobile: 40px;
203 - --darkify_switch_position_from_top_left_top_in_mobile: 40px;
204 - --darkify_switch_position_from_top_left_left_in_mobile: 40px;
205 - --darkify_switch_position_from_bottom_left_bottom_in_mobile: 40px;
206 - --darkify_switch_position_from_bottom_left_left_in_mobile: 40px;
207 - --darkify_switch_tooltip_bg_color: #142434;
208 - --darkify_switch_tooltip_text_color: #b0cbe7;
209 -}
210 426 .darkify_switch,
211 427 .darkify_switch * {
212 428 box-sizing: border-box;
213 429 }
@@ -218,14 +434,14 @@
218 434 position: fixed;
219 435 z-index: 99999;
220 436 }
221 437 .darkify_switch.darkify_top_left {
222 - top: var(--darkify_switch_position_from_top_left_left_in_mobile);
223 - left: var(--darkify_switch_position_from_top_left_left_in_mobile);
438 + top: var(--darkify_switch_position_from_top_left_top);
439 + left: var(--darkify_switch_position_from_top_left_left);
224 440 }
225 441 .darkify_switch.darkify_top_right {
226 - top: var(--darkify_switch_position_from_top_right_top_in_mobile);
227 - right: var(--darkify_switch_position_from_top_right_right_in_mobile);
442 + top: var(--darkify_switch_position_from_top_right_top);
443 + right: var(--darkify_switch_position_from_top_right_right);
228 444 }
229 445 .darkify_switch.darkify_bottom_left {
230 446 bottom: var(--darkify_switch_position_from_bottom_left_bottom);
231 447 left: var(--darkify_switch_position_from_bottom_left_left);
@@ -235,9 +451,8 @@
235 451 right: var(--darkify_switch_position_from_bottom_right_right);
236 452 }
237 453 .darkify_switch.darkify_absolute_position {
238 454 position: absolute;
239 - z-index: unset;
240 455 }
241 456
242 457 @media only screen and (max-width: 600px) {
243 458 .darkify_switch.darkify_hide_on_mobile {
@@ -285,11 +500,12 @@
285 500 color: var(--darkify_switch_tooltip_text_color);
286 501 font-size: 12px;
287 502 text-align: center;
288 503 border-radius: 0;
289 - padding: 5px 0;
504 + padding: 5px 5px;
290 505 position: absolute;
291 506 z-index: 1;
507 + border-radius: 3px;
292 508 }
293 509 .darkify_tooltip .darkify_tooltiptext::after {
294 510 content: "";
295 511 position: absolute;
@@ -348,44 +564,337 @@
348 564
349 565 /* ==============
350 566 Switch Style
351 567 ============== */
568 +
352 569 .darkify_switch_style {
353 - --darkify_switch_width_height: 60px;
354 - --darkify_switch_icon_size: 50px;
355 - --darkify_switch_border_radius: 7px;
356 - --darkify_switch_light_mode_bg: #121116;
357 - --darkify_switch_dark_mode_bg: #ffffff;
358 - --darkify_switch_light_mode_color: #ffffff;
359 - --darkify_switch_dark_mode_color: #121116;
570 + cursor: pointer;
571 + z-index: 9999;
572 + width: calc(60px * var(--darkify-switch-scale, 1));
573 + height: calc(60px * var(--darkify-switch-scale, 1));
574 + border-radius: var(--darkify_switch_border_radius);
575 + background: var(--darkify_switch_light_mode_bg);
576 + display: flex;
577 + align-items: center;
578 + justify-content: center;
579 + border-width: var(--darkify_switch_border);
580 + border-style: solid;
581 + border-color: var(--darkify_switch_border_light_color);
360 582 }
361 -.darkify_switch_style{
362 - cursor: pointer;
363 - z-index: 9999;
364 - width: var(--darkify_switch_width_height);
365 - height: var(--darkify_switch_width_height);
366 - border-radius: var(--darkify_switch_border_radius);
367 - background: var(--darkify_switch_light_mode_bg);
368 - display: flex;
369 - align-items: center;
370 - justify-content: center;
371 - fill: var(--darkify_switch_light_mode_icon_color);
372 - stroke: var(--darkify_switch_light_mode_icon_color);
583 +
584 +.darkify_dark_mode_enabled .darkify_switch_style {
585 + border-color: var(--darkify_switch_border_dark_color);
373 586 }
374 -.darkify_switch_style .theme-toggle{
375 - display: flex;
376 - align-items: center;
377 - justify-content: center;
587 +.darkify_switch_style .theme-toggle {
588 + display: flex;
589 + align-items: center;
590 + justify-content: center;
378 591 }
379 592 .darkify_switch_style svg {
380 - width: var(--darkify_switch_icon_size);
381 - height: var(--darkify_switch_icon_size);
382 - color: var(--darkify_switch_light_mode_color);
383 - stroke: var(--darkify_switch_light_mode_color);
593 + width: calc(40px * var(--darkify-switch-scale, 1));
594 + height: calc(40px * var(--darkify-switch-scale, 1));
595 + color: var(--darkify_switch_light_mode_color);
596 + stroke: var(--darkify_switch_light_mode_color);
384 597 }
385 -.darkify_dark_mode_enabled .darkify_switch_style{
386 - background: var(--darkify_switch_dark_mode_bg);
598 +.darkify_dark_mode_enabled .darkify_switch_style {
599 + background: var(--darkify_switch_dark_mode_bg);
387 600 }
388 601 .darkify_dark_mode_enabled .darkify_switch_style svg {
389 - color: var(--darkify_switch_dark_mode_color);
390 - stroke: var(--darkify_switch_dark_mode_color);
391 -}
602 + color: var(--darkify_switch_dark_mode_color);
603 + stroke: var(--darkify_switch_dark_mode_color);
604 +}
605 +.switch-orbit,
606 +.switch-duality,
607 +.switch-dual,
608 +.switch-shift {
609 + box-sizing: content-box;
610 +}
611 +.darkify_dark_mode_enabled
612 + .block-editor-page.post-content-style-boxed
613 + .editor-styles-wrapper:before {
614 + background-color: unset;
615 +}
616 +.darkify_dark_mode_enabled h3#color-palette-1-0,
617 +.darkify_dark_mode_enabled .components-color-palette__custom-color-name {
618 + color: var(--darkify_dark_mode_text_color)!important;
619 +}
620 +.darkify-dropdown {
621 + position: relative;
622 + width: 160px;
623 + margin-left: 8px;
624 +}
625 +
626 +.darkify-dropdown .darkify-selected {
627 + padding: 5px;
628 + background: #fff;
629 + color: #000;
630 + cursor: pointer;
631 + border-radius: 3px;
632 + border: 1px solid #c0c0c0;
633 +}
634 +
635 +.darkify-dropdown .darkify-options {
636 + display: none;
637 + position: absolute;
638 + width: 100%;
639 + background: #fff;
640 + border-radius: 6px;
641 + margin-top: 5px;
642 + overflow: hidden;
643 + z-index: 1000;
644 + box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
645 + color: #000;
646 + top: 30px;
647 +}
648 +
649 +.darkify-dropdown .darkify-options.show {
650 + display: block;
651 +}
652 +
653 +.darkify-dropdown .darkify-option {
654 + padding: 8px;
655 + cursor: pointer;
656 + display: flex;
657 + align-items: center;
658 + gap: 4px;
659 +}
660 +.darkify-dropdown .darkify-pro-option {
661 + cursor: not-allowed;
662 + opacity: 0.55;
663 + pointer-events: none;
664 + gap: 4px;
665 +}
666 +.darkify-option-pro-badge {
667 + margin-left: auto;
668 + font-size: 10px;
669 + font-weight: 600;
670 + background: #cbd6df;
671 + color: #5e6e7d;
672 + padding: 2px 5px;
673 + border-radius: 3px;
674 + white-space: nowrap;
675 + flex-shrink: 0;
676 +}
677 +.darkify-dropdown .darkify-selected {
678 + display: flex;
679 + align-items: center;
680 + width: 100%;
681 + gap: 4px;
682 +}
683 +.darkify-dropdown .theme_color {
684 + display: inline-block;
685 + width: 20px;
686 + height: 20px;
687 + border-radius: 50%;
688 + border: 1px solid gray;
689 +}
690 +.darkify-dropdown .default {
691 + background-color: #fff;
692 +}
693 +/*
694 + * "Auto" has no single colour to show — Dark Reader derives one per element —
695 + * so the swatch shows a gradient rather than claiming a flat value the way the
696 + * named presets legitimately can.
697 + */
698 +.darkify-dropdown .auto_palette {
699 + background-image: linear-gradient(135deg, #0f0f0f 0%, #3a3a3a 50%, #8f8f8f 100%);
700 +}
701 +.darkify-dropdown .carbon_mist {
702 + background-color: #171717;
703 +}
704 +.darkify-dropdown .midnight_reverie {
705 + background-color: #4e478d;
706 +}
707 +.darkify-dropdown .verdant_depths {
708 + background-color: #073d2f;
709 +}
710 +.darkify-dropdown .celestial_tide {
711 + background-color: #144e78;
712 +}
713 +.darkify-dropdown .emberwood {
714 + background-color: #372911;
715 +}
716 +.darkify-dropdown .glacier_drift {
717 + background-color: #123d52;
718 +}
719 +.darkify-dropdown .indigo_veil {
720 + background-color: #46598c;
721 +}
722 +.darkify-dropdown .duskmire {
723 + background-color: #403953;
724 +}
725 +.darkify-dropdown .tidal_frost {
726 + background-color: #286f8d;
727 +}
728 +.darkify-dropdown .blue_bastion {
729 + background-color: #244892;
730 +}
731 +.darkify-dropdown .crimson_veil {
732 + background-color: #440649;
733 +}
734 +
735 +.darkify_dark_mode_enabled .darkify-dropdown,
736 +.darkify_dark_mode_enabled .darkify-options.show {
737 + background-color: var(--darkify_dark_mode_bg) !important;
738 +}
739 +
740 +/* Switch Attention Effects */
741 +@keyframes darkify_attention_pulse {
742 + 0%, 100% { transform: scale(1); }
743 + 50% { transform: scale(1.1); }
744 +}
745 +@keyframes darkify_attention_radiance {
746 + 0%, 100% { box-shadow: 0 0 0 0 rgba(100, 100, 100, 0.45); }
747 + 50% { box-shadow: 0 0 0 14px rgba(100, 100, 100, 0); }
748 +}
749 +@keyframes darkify_attention_leap {
750 + 0%, 55%, 100% { transform: translateY(0); }
751 + 30% { transform: translateY(-14px); }
752 + 45% { transform: translateY(-8px); }
753 +}
754 +@keyframes darkify_attention_swing {
755 + 0%, 100% { transform: rotate(0deg); transform-origin: center bottom; }
756 + 20% { transform: rotate(-9deg); transform-origin: center bottom; }
757 + 40% { transform: rotate(7deg); transform-origin: center bottom; }
758 + 60% { transform: rotate(-5deg); transform-origin: center bottom; }
759 + 80% { transform: rotate(3deg); transform-origin: center bottom; }
760 +}
761 +@keyframes darkify_attention_drift {
762 + 0%, 100% { transform: translateY(0); }
763 + 50% { transform: translateY(-8px); }
764 +}
765 +@keyframes darkify_attention_nudge {
766 + 0%, 65%, 100% { transform: translateX(0); }
767 + 10% { transform: translateX(-6px); }
768 + 20% { transform: translateX(6px); }
769 + 30% { transform: translateX(-4px); }
770 + 40% { transform: translateX(4px); }
771 + 50% { transform: translateX(-2px); }
772 + 57% { transform: translateX(2px); }
773 +}
774 +.darkify_switch.darkify_attention_pulse {
775 + animation: darkify_attention_pulse 2s ease-in-out 2s infinite;
776 +}
777 +.darkify_switch.darkify_attention_radiance {
778 + animation: darkify_attention_radiance 2s ease-in-out 2s infinite;
779 +}
780 +.darkify_switch.darkify_attention_leap {
781 + animation: darkify_attention_leap 2.5s ease-in-out 2s infinite;
782 +}
783 +.darkify_switch.darkify_attention_swing {
784 + animation: darkify_attention_swing 1.6s ease-in-out 2s infinite;
785 +}
786 +.darkify_switch.darkify_attention_drift {
787 + animation: darkify_attention_drift 3s ease-in-out 2s infinite;
788 +}
789 +.darkify_switch.darkify_attention_nudge {
790 + animation: darkify_attention_nudge 2.5s ease-in-out 2s infinite;
791 +}
792 +.darkify_switch.darkify_attention_pulse:hover,
793 +.darkify_switch.darkify_attention_radiance:hover,
794 +.darkify_switch.darkify_attention_leap:hover,
795 +.darkify_switch.darkify_attention_swing:hover,
796 +.darkify_switch.darkify_attention_drift:hover,
797 +.darkify_switch.darkify_attention_nudge:hover {
798 + animation-play-state: paused;
799 +}
800 +/*
801 + * Transition suppression for the duration of an engine pass.
802 + *
803 + * The engine classifies an element from its computed colours, and a colour
804 + * mid-transition computes to an interpolated value that belongs to neither the
805 + * start nor the end state — so a pass that runs while the page is animating
806 + * reads colours the design never actually paints. Suppressing transitions for
807 + * the length of the pass makes every read a settled one.
808 + *
809 + * This replaces an inline `transition-property: none !important` that was
810 + * written to, and then removed from, every element individually. Writing a
811 + * style and then reading a computed style off the same element forces a
812 + * synchronous style recalculation, so that pattern cost one full recalc per
813 + * element; as one class on the root it costs one invalidation per pass.
814 + *
815 + * `!important` is warranted here and is the reason the declaration can stay a
816 + * single rule: it has to beat inline transitions written by builders and
817 + * animation libraries, which is precisely the case it exists to neutralise. It
818 + * is present only while a pass is running — never in the page's resting state.
819 + */
820 +/*
821 + * The switcher is deliberately outside this suppression, and leaving it in was
822 + * a real bug: it silently removed the toggle's animation.
823 + *
824 + * The switcher is the one animated thing on the page that the engine does not
825 + * manage — it never receives `darkify_processed`, its colours are never read to
826 + * classify it, and its whole visual job is to animate between the two states.
827 + * Suppressing transitions on it therefore protects nothing and costs the
828 + * feature.
829 + *
830 + * The damage is not obvious from reading the rule, because the class is added
831 + * and removed inside a single synchronous task, so it is never painted. What
832 + * matters is that the pass calls `getComputedStyle` thousands of times while
833 + * the class is on, and every one of those forces a style recalculation. A
834 + * recalculation that sees `transition-property: none` *cancels the transitions
835 + * already running* — and the switcher's transitions started moments earlier,
836 + * when the state class flipped. Removing the class afterwards does not revive
837 + * them; the values have already been committed to their end state. Measured on
838 + * the stress page: 17 transitions created on `d`, `opacity` and `transform`,
839 + * all with `currentTime` still 0, gone by the next frame — the toggle snapped
840 + * instead of animating.
841 + *
842 + * `.darkify_ignore` is excluded for the same reason it is excluded from every
843 + * other rule in this file: it marks a subtree the plugin has been told to keep
844 + * its hands off, and cancelling its animations is exactly the interference the
845 + * marker exists to prevent.
846 + *
847 + * This costs nothing. The exclusion is evaluated only while a pass is running,
848 + * and it removes work rather than adding it — the excluded subtrees are the
849 + * ones the engine was never going to read.
850 + */
851 +html.darkify_suspend_transitions,
852 +html.darkify_suspend_transitions
853 + *:not(
854 + .darkify_switch,
855 + .darkify_switch *,
856 + .darkify_ignore,
857 + .darkify_ignore *
858 + ) {
859 + transition-property: none !important;
860 +}
861 +
862 +/*
863 + * The same suppression, scoped to a single element — and now to a single case.
864 + *
865 + * The rule above is correct for the two passes that read the whole document —
866 + * the first walk and the dark-mode state sweep — because at those moments the
867 + * page is either not yet interactive or is being repainted wholesale anyway.
868 + * This rule covers the incremental passes, where exactly one of the two things
869 + * that reach them wants it:
870 + *
871 + * - An element being coloured for the FIRST time (a node that arrived after
872 + * the initial walk) gets the class. Without it, dark mode *animates* onto
873 + * the element and it fades from its light colour to its dark one in full
874 + * view. On a hard reload, with nothing in cache, far more of the page
875 + * arrives late and is coloured here rather than by the walk the FOUC guard
876 + * hides — which is what made backgrounds visibly wash from white to dark.
877 + *
878 + * - An element being RE-READ because its class list changed (an accordion
879 + * opening, a dropdown, a hover state) must NOT get it, so the animation
880 + * that triggered the pass still eases. Applying it here was what made those
881 + * snap to their end state.
882 + *
883 + * The class is applied around the read and released on the next frame rather
884 + * than synchronously (see darkify_release_no_transition in client_main.js): a
885 + * same-task removal means the browser only ever computes the finished state —
886 + * new colour with transitions live — and eases into it, which is the very thing
887 + * being prevented.
888 + *
889 + * `transition-property` is not inherited, so this cancels the element's own
890 + * transitions and nothing below it. It is also a reasonable thing to put on an
891 + * element by hand.
892 + */
893 +.darkify_no_transition:not(
894 + .darkify_switch,
895 + .darkify_switch *,
896 + .darkify_ignore,
897 + .darkify_ignore *
898 + ) {
899 + transition-property: none !important;
900 +}