PluginProbe
Darkify – Dark Mode & Night Mode for Website & Admin (Dark Theme Included) / 2.0.4
Darkify – Dark Mode & Night Mode for Website & Admin (Dark Theme Included) v2.0.4
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
darkify / src / assets / css / client_main.css

client_main.css in Darkify – Dark Mode & Night Mode for Website & Admin (Dark Theme Included) 2.0.4, at src/assets/css/client_main.css

804 lines 26.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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
19 .darkify_dark_mode_enabled
20 .darkify_style_all:not(
21 .darkify_switch,
22 .darkify_switch *,
23 .darkify_ignore,
24 .darkify_ignore *
25 ) {
26 background-color: var(--darkify_dark_mode_bg) !important;
27 color: var(--darkify_dark_mode_text_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;
32 }
33 .darkify_dark_mode_enabled
34 .darkify_style_bg_txt:not(
35 .darkify_switch,
36 .darkify_switch *,
37 .darkify_ignore,
38 .darkify_ignore *
39 ) {
40 background-color: var(--darkify_dark_mode_bg) !important;
41 color: var(--darkify_dark_mode_text_color) !important;
42 }
43 .darkify_dark_mode_enabled
44 .darkify_style_bg_border:not(
45 .darkify_switch,
46 .darkify_switch *,
47 .darkify_ignore,
48 .darkify_ignore *
49 ) {
50 background-color: var(--darkify_dark_mode_bg) !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;
55 }
56 .darkify_dark_mode_enabled
57 .darkify_style_txt_border:not(
58 .darkify_switch,
59 .darkify_switch *,
60 .darkify_ignore,
61 .darkify_ignore *
62 ) {
63 color: var(--darkify_dark_mode_text_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;
68 }
69 .darkify_dark_mode_enabled
70 .darkify_style_bg:not(
71 .darkify_switch,
72 .darkify_switch *,
73 .darkify_ignore,
74 .darkify_ignore *
75 ) {
76 background-color: var(--darkify_dark_mode_bg) !important;
77 }
78 .darkify_dark_mode_enabled
79 .darkify_style_txt:not(
80 .darkify_switch,
81 .darkify_switch *,
82 .darkify_ignore,
83 .darkify_ignore *
84 ) {
85 color: var(--darkify_dark_mode_text_color) !important;
86 }
87 .darkify_dark_mode_enabled
88 .darkify_style_border:not(
89 .darkify_switch,
90 .darkify_switch *,
91 .darkify_ignore,
92 .darkify_ignore *
93 ) {
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;
98 }
99 .darkify_dark_mode_enabled
100 .darkify_style_secondary_bg:not(
101 .darkify_switch,
102 .darkify_switch *,
103 .darkify_ignore,
104 .darkify_ignore *
105 ) {
106 background-color: var(--darkify_dark_mode_secondary_bg) !important;
107 }
108
109 /*Handle Link Style*/
110 .darkify_dark_mode_enabled
111 .darkify_style_link:not(
112 .darkify_switch,
113 .darkify_switch *,
114 .darkify_ignore,
115 .darkify_ignore *,
116 .darkify-nav ul li a
117 ) {
118 color: var(--darkify_dark_mode_link_color) !important;
119 }
120 .darkify_dark_mode_enabled
121 .darkify_style_link:not(
122 .darkify_switch,
123 .darkify_switch *,
124 .darkify_ignore,
125 .darkify_ignore *
126 ):hover {
127 color: var(--darkify_dark_mode_link_hover_color) !important;
128 }
129
130 /*Handle Form Element Style*/
131 .darkify_dark_mode_enabled
132 .darkify_style_form_element:not(
133 .darkify_switch,
134 .darkify_switch *,
135 .darkify_ignore,
136 .darkify_ignore *
137 ) {
138 background-color: var(--darkify_dark_mode_input_bg) !important;
139 color: var(--darkify_dark_mode_input_text_color) !important;
140 }
141 .darkify_dark_mode_enabled
142 .darkify_style_form_element:not(
143 .darkify_switch,
144 .darkify_switch *,
145 .darkify_ignore,
146 .darkify_ignore *
147 )::placeholder {
148 color: var(--darkify_dark_mode_input_placeholder_color) !important;
149 }
150
151 /*Handle Button Style*/
152 .darkify_dark_mode_enabled
153 .darkify_style_button:not(
154 .darkify_switch,
155 .darkify_switch *,
156 .darkify_ignore,
157 .darkify_ignore *
158 ) {
159 background-color: var(--darkify_dark_mode_btn_bg) !important;
160 color: var(--darkify_dark_mode_btn_text_color) !important;
161 /*
162 * Buttons carry their own border token rather than the page's.
163 *
164 * The classifier takes `darkify_style_all` off an element the moment it calls
165 * it a button, so until these four lines existed a button's border was the
166 * one colour on the page dark mode never touched: an outline button kept the
167 * light design's brand edge — a teal ring around a grey fill — and no setting
168 * could reach it. A button also cannot simply borrow the generic border
169 * colour, because its border belongs to the button's own colour set: it is
170 * usually the fill or a shade of it, which is why the default for these
171 * tokens mirrors the button background.
172 */
173 border-right-color: var(--darkify_dark_mode_btn_border_color) !important;
174 border-left-color: var(--darkify_dark_mode_btn_border_color) !important;
175 border-top-color: var(--darkify_dark_mode_btn_border_color) !important;
176 border-bottom-color: var(--darkify_dark_mode_btn_border_color) !important;
177 }
178 /* the hover state */
179 .darkify_dark_mode_enabled
180 .darkify_style_button:not(
181 .darkify_switch,
182 .darkify_switch *,
183 .darkify_ignore,
184 .darkify_ignore *
185 ):hover {
186 background-color: var(--darkify_dark_mode_btn_hover_bg) !important;
187 color: var(--darkify_dark_mode_btn_text_hover_color) !important;
188 border-right-color: var(--darkify_dark_mode_btn_hover_border_color) !important;
189 border-left-color: var(--darkify_dark_mode_btn_hover_border_color) !important;
190 border-top-color: var(--darkify_dark_mode_btn_hover_border_color) !important;
191 border-bottom-color: var(--darkify_dark_mode_btn_hover_border_color) !important;
192 }
193
194
195 /* ========================
196 Borders the design does not draw
197 ===========================*/
198 /*
199 * A side marked here had a width in the light design but no colour — the
200 * `border: 8px solid transparent` idiom themes and block grids use for gutters
201 * and alignment. It occupies space and paints nothing.
202 *
203 * The rules above cannot tell those sides apart from real ones: they set all
204 * four border colours at once, because a class cannot carry per-side
205 * information. Painting a gutter turns invisible spacing into a visible line,
206 * and an element ringed by four of them grows a box that the light design never
207 * had — the effect that made WooCommerce product cards appear boxed in dark
208 * mode while looking open in light.
209 *
210 * The classifier stamps these markers on exactly the sides it measured as
211 * transparent, so each one is pinned back to transparent regardless of which
212 * colour rule matched. They repeat the `:not(...)` shape of the rules they
213 * override so the specificity matches, and sit after them so they win the tie.
214 */
215 .darkify_dark_mode_enabled
216 .darkify_border_keep_top:not(
217 .darkify_switch,
218 .darkify_switch *,
219 .darkify_ignore,
220 .darkify_ignore *
221 ) {
222 border-top-color: transparent !important;
223 }
224 .darkify_dark_mode_enabled
225 .darkify_border_keep_right:not(
226 .darkify_switch,
227 .darkify_switch *,
228 .darkify_ignore,
229 .darkify_ignore *
230 ) {
231 border-right-color: transparent !important;
232 }
233 .darkify_dark_mode_enabled
234 .darkify_border_keep_bottom:not(
235 .darkify_switch,
236 .darkify_switch *,
237 .darkify_ignore,
238 .darkify_ignore *
239 ) {
240 border-bottom-color: transparent !important;
241 }
242 .darkify_dark_mode_enabled
243 .darkify_border_keep_left:not(
244 .darkify_switch,
245 .darkify_switch *,
246 .darkify_ignore,
247 .darkify_ignore *
248 ) {
249 border-left-color: transparent !important;
250 }
251
252 /* ========================
253 Pre-paint baseline (FOUC)
254 ===========================*/
255 /*
256 * Dark mode is decided in the <head>, but the colours come from a DOM walk that
257 * cannot start until the DOM exists. Something has to cover that gap.
258 *
259 * It cannot be a colour wash on the elements themselves. The engine derives
260 * each dark colour by *reading* the element's computed light colour, so any
261 * rule that restyles elements beforehand destroys its input — everything reads
262 * back as the wash and nothing can be derived.
263 *
264 * A `brightness()` filter on <html> used to fill the gap. It painted only, so
265 * `getComputedStyle` still reported the design's real colours, but it dimmed
266 * the *whole viewport* — on a slow page that reads as a grey overlay sitting
267 * over the site for the entire load, and it repeats on every navigation. The
268 * filter is gone for that reason.
269 *
270 * What is left is the page backdrop alone: the root paints the configured dark
271 * background from the first frame, so the gap before the walk is a dark page
272 * rather than a white one. Content that has already painted keeps its light
273 * colours for those few frames — a much smaller artefact than dimming the
274 * entire viewport.
275 *
276 * Deliberately temporary: the class comes off the moment the first walk has
277 * assigned real colours.
278 */
279 html.darkify_dark_mode_enabled.darkify_prepaint {
280 background-color: var(--darkify_dark_mode_bg) !important;
281 }
282
283 /* ========================
284 Admin Bar Menu Design
285 ===========================*/
286 .darkify_admin_bar_switch_container {
287 cursor: pointer !important;
288 display: flex;
289 align-items: center;
290 justify-content: center;
291 width: 40px !important;
292 height: 32px !important;
293 }
294 /* On Darkify's own settings/help screens the admin-bar node is always rendered
295 so the React admin can reveal it the instant "Admin Panel Dark Mode" is
296 switched on (see WpAdminBarBridge) rather than only after a reload. It starts
297 hidden whenever the option is off. */
298 .darkify_admin_bar_switch_container.darkify_admin_bar_hidden {
299 display: none !important;
300 }
301 .darkify_admin_bar_switch_container .ab-item {
302 height: 18px !important;
303 cursor: pointer !important;
304 background-color: #ffffff !important;
305 -webkit-mask: url(../../Admin/assets/images/switch_apple_light.svg) no-repeat center;
306 mask: url(../../Admin/assets/images/switch_apple_light.svg) no-repeat center;
307 }
308 .darkify_dark_mode_enabled .darkify_admin_bar_switch_container .ab-item {
309 -webkit-mask: url(../../Admin/assets/images/switch_apple_dark.svg) no-repeat center;
310 mask: url(../../Admin/assets/images/switch_apple_dark.svg) no-repeat center;
311 }
312
313 /* ========================
314 Block Editor Menu Design
315 ===========================*/
316 .darkify_block_editor_switch {
317 height: 33px;
318 cursor: pointer;
319 -webkit-appearance: none;
320 -moz-appearance: none;
321 outline: 0;
322 border: 0;
323 background: #121116;
324 border-radius: 3px;
325 padding: 0 12px;
326 margin-right: 8px;
327 }
328 .darkify_dark_mode_enabled .darkify_block_editor_switch {
329 background: #ffffff;
330 }
331 .darkify_block_editor_switch .icon {
332 width: 20px;
333 height: 20px;
334 background-color: #ffffff !important;
335 -webkit-mask: url(../../Admin/assets/images/switch_apple_light.svg) no-repeat center;
336 mask: url(../../Admin/assets/images/switch_apple_light.svg) no-repeat center;
337 }
338
339 .darkify_dark_mode_enabled .darkify_block_editor_switch .icon {
340 background-color: #171717 !important;
341 -webkit-mask: url(../../Admin/assets/images/switch_apple_dark.svg) no-repeat center;
342 mask: url(../../Admin/assets/images/switch_apple_dark.svg) no-repeat center;
343 }
344
345 /* ========================
346 Switch Design
347 ===========================*/
348
349 .darkify_switch,
350 .darkify_switch * {
351 box-sizing: border-box;
352 }
353 .darkify_switch.darkify_top_left,
354 .darkify_switch.darkify_top_right,
355 .darkify_switch.darkify_bottom_left,
356 .darkify_switch.darkify_bottom_right {
357 position: fixed;
358 z-index: 99999;
359 }
360 .darkify_switch.darkify_top_left {
361 top: var(--darkify_switch_position_from_top_left_top);
362 left: var(--darkify_switch_position_from_top_left_left);
363 }
364 .darkify_switch.darkify_top_right {
365 top: var(--darkify_switch_position_from_top_right_top);
366 right: var(--darkify_switch_position_from_top_right_right);
367 }
368 .darkify_switch.darkify_bottom_left {
369 bottom: var(--darkify_switch_position_from_bottom_left_bottom);
370 left: var(--darkify_switch_position_from_bottom_left_left);
371 }
372 .darkify_switch.darkify_bottom_right {
373 bottom: var(--darkify_switch_position_from_bottom_right_bottom);
374 right: var(--darkify_switch_position_from_bottom_right_right);
375 }
376 .darkify_switch.darkify_absolute_position {
377 position: absolute;
378 }
379
380 @media only screen and (max-width: 600px) {
381 .darkify_switch.darkify_hide_on_mobile {
382 display: none;
383 }
384 }
385
386 @media only screen and (max-width: 600px) {
387 .darkify_switch.darkify_top_left_in_mobile,
388 .darkify_switch.darkify_top_right_in_mobile,
389 .darkify_switch.darkify_bottom_left_in_mobile,
390 .darkify_switch.darkify_bottom_right_in_mobile {
391 position: fixed;
392 }
393 .darkify_switch.darkify_top_left_in_mobile {
394 top: var(--darkify_switch_position_from_top_left_top_in_mobile);
395 left: var(--darkify_switch_position_from_top_left_left_in_mobile);
396 bottom: unset;
397 right: unset;
398 }
399 .darkify_switch.darkify_top_right_in_mobile {
400 top: var(--darkify_switch_position_from_top_right_top_in_mobile);
401 right: var(--darkify_switch_position_from_top_right_right_in_mobile);
402 bottom: unset;
403 left: unset;
404 }
405 .darkify_switch.darkify_bottom_left_in_mobile {
406 bottom: var(--darkify_switch_position_from_bottom_left_bottom_in_mobile);
407 left: var(--darkify_switch_position_from_bottom_left_left_in_mobile);
408 top: unset;
409 right: unset;
410 }
411 .darkify_switch.darkify_bottom_right_in_mobile {
412 bottom: var(--darkify_switch_position_from_bottom_right_bottom_in_mobile);
413 right: var(--darkify_switch_position_from_bottom_right_right_in_mobile);
414 top: unset;
415 left: unset;
416 }
417 }
418
419 .darkify_tooltip .darkify_tooltiptext {
420 visibility: hidden;
421 width: 120px;
422 background-color: var(--darkify_switch_tooltip_bg_color);
423 color: var(--darkify_switch_tooltip_text_color);
424 font-size: 12px;
425 text-align: center;
426 border-radius: 0;
427 padding: 5px 5px;
428 position: absolute;
429 z-index: 1;
430 border-radius: 3px;
431 }
432 .darkify_tooltip .darkify_tooltiptext::after {
433 content: "";
434 position: absolute;
435 border-width: 5px;
436 border-style: solid;
437 }
438 .darkify_tooltip:hover .darkify_tooltiptext {
439 visibility: visible;
440 }
441 .darkify_tooltip.darkify_tooltip_top .darkify_tooltiptext {
442 bottom: calc(100% + 10px);
443 left: 50%;
444 margin-left: -60px;
445 }
446 .darkify_tooltip.darkify_tooltip_top .darkify_tooltiptext::after {
447 left: 50%;
448 margin-left: -5px;
449 top: 100%;
450 border-color: var(--darkify_switch_tooltip_bg_color) transparent transparent
451 transparent;
452 }
453 .darkify_tooltip.darkify_tooltip_bottom .darkify_tooltiptext {
454 top: calc(100% + 10px);
455 left: 50%;
456 margin-left: -60px;
457 }
458 .darkify_tooltip.darkify_tooltip_bottom .darkify_tooltiptext::after {
459 left: 50%;
460 margin-left: -5px;
461 bottom: 100%;
462 border-color: transparent transparent var(--darkify_switch_tooltip_bg_color)
463 transparent;
464 }
465 .darkify_tooltip.darkify_tooltip_left .darkify_tooltiptext {
466 right: calc(100% + 10px);
467 top: calc(50% - 15px);
468 }
469 .darkify_tooltip.darkify_tooltip_left .darkify_tooltiptext::after {
470 top: 50%;
471 left: 100%;
472 margin-top: -5px;
473 border-color: transparent transparent transparent
474 var(--darkify_switch_tooltip_bg_color);
475 }
476 .darkify_tooltip.darkify_tooltip_right .darkify_tooltiptext {
477 left: calc(100% + 10px);
478 top: calc(50% - 15px);
479 }
480 .darkify_tooltip.darkify_tooltip_right .darkify_tooltiptext::after {
481 top: 50%;
482 right: 100%;
483 margin-top: -5px;
484 border-color: transparent var(--darkify_switch_tooltip_bg_color) transparent
485 transparent;
486 }
487
488 /* ==============
489 Switch Style
490 ============== */
491
492 .darkify_switch_style {
493 cursor: pointer;
494 z-index: 9999;
495 width: calc(60px * var(--darkify-switch-scale, 1));
496 height: calc(60px * var(--darkify-switch-scale, 1));
497 border-radius: var(--darkify_switch_border_radius);
498 background: var(--darkify_switch_light_mode_bg);
499 display: flex;
500 align-items: center;
501 justify-content: center;
502 border-width: var(--darkify_switch_border);
503 border-style: solid;
504 border-color: var(--darkify_switch_border_light_color);
505 }
506
507 .darkify_dark_mode_enabled .darkify_switch_style {
508 border-color: var(--darkify_switch_border_dark_color);
509 }
510 .darkify_switch_style .theme-toggle {
511 display: flex;
512 align-items: center;
513 justify-content: center;
514 }
515 .darkify_switch_style svg {
516 width: calc(40px * var(--darkify-switch-scale, 1));
517 height: calc(40px * var(--darkify-switch-scale, 1));
518 color: var(--darkify_switch_light_mode_color);
519 stroke: var(--darkify_switch_light_mode_color);
520 }
521 .darkify_dark_mode_enabled .darkify_switch_style {
522 background: var(--darkify_switch_dark_mode_bg);
523 }
524 .darkify_dark_mode_enabled .darkify_switch_style svg {
525 color: var(--darkify_switch_dark_mode_color);
526 stroke: var(--darkify_switch_dark_mode_color);
527 }
528 .switch-orbit,
529 .switch-duality,
530 .switch-dual,
531 .switch-shift {
532 box-sizing: content-box;
533 }
534 .darkify_dark_mode_enabled
535 .block-editor-page.post-content-style-boxed
536 .editor-styles-wrapper:before {
537 background-color: unset;
538 }
539 .darkify_dark_mode_enabled h3#color-palette-1-0,
540 .darkify_dark_mode_enabled .components-color-palette__custom-color-name {
541 color: var(--darkify_dark_mode_text_color)!important;
542 }
543 .darkify-dropdown {
544 position: relative;
545 width: 160px;
546 margin-left: 8px;
547 }
548
549 .darkify-dropdown .darkify-selected {
550 padding: 5px;
551 background: #fff;
552 color: #000;
553 cursor: pointer;
554 border-radius: 3px;
555 border: 1px solid #c0c0c0;
556 }
557
558 .darkify-dropdown .darkify-options {
559 display: none;
560 position: absolute;
561 width: 100%;
562 background: #fff;
563 border-radius: 6px;
564 margin-top: 5px;
565 overflow: hidden;
566 z-index: 1000;
567 box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
568 color: #000;
569 top: 30px;
570 }
571
572 .darkify-dropdown .darkify-options.show {
573 display: block;
574 }
575
576 .darkify-dropdown .darkify-option {
577 padding: 8px;
578 cursor: pointer;
579 display: flex;
580 align-items: center;
581 gap: 4px;
582 }
583 .darkify-dropdown .darkify-pro-option {
584 cursor: not-allowed;
585 opacity: 0.55;
586 pointer-events: none;
587 gap: 4px;
588 }
589 .darkify-option-pro-badge {
590 margin-left: auto;
591 font-size: 10px;
592 font-weight: 600;
593 background: #cbd6df;
594 color: #5e6e7d;
595 padding: 2px 5px;
596 border-radius: 3px;
597 white-space: nowrap;
598 flex-shrink: 0;
599 }
600 .darkify-dropdown .darkify-selected {
601 display: flex;
602 align-items: center;
603 width: 100%;
604 gap: 4px;
605 }
606 .darkify-dropdown .theme_color {
607 display: inline-block;
608 width: 20px;
609 height: 20px;
610 border-radius: 50%;
611 border: 1px solid gray;
612 }
613 .darkify-dropdown .default {
614 background-color: #fff;
615 }
616 .darkify-dropdown .carbon_mist {
617 background-color: #171717;
618 }
619 .darkify-dropdown .midnight_reverie {
620 background-color: #4e478d;
621 }
622 .darkify-dropdown .verdant_depths {
623 background-color: #073d2f;
624 }
625 .darkify-dropdown .celestial_tide {
626 background-color: #144e78;
627 }
628 .darkify-dropdown .emberwood {
629 background-color: #372911;
630 }
631 .darkify-dropdown .glacier_drift {
632 background-color: #123d52;
633 }
634 .darkify-dropdown .indigo_veil {
635 background-color: #46598c;
636 }
637 .darkify-dropdown .duskmire {
638 background-color: #403953;
639 }
640 .darkify-dropdown .tidal_frost {
641 background-color: #286f8d;
642 }
643 .darkify-dropdown .blue_bastion {
644 background-color: #244892;
645 }
646 .darkify-dropdown .crimson_veil {
647 background-color: #440649;
648 }
649
650 .darkify_dark_mode_enabled .darkify-dropdown,
651 .darkify_dark_mode_enabled .darkify-options.show {
652 background-color: var(--darkify_dark_mode_bg) !important;
653 }
654
655 /* Switch Attention Effects */
656 @keyframes darkify_attention_pulse {
657 0%, 100% { transform: scale(1); }
658 50% { transform: scale(1.1); }
659 }
660 @keyframes darkify_attention_radiance {
661 0%, 100% { box-shadow: 0 0 0 0 rgba(100, 100, 100, 0.45); }
662 50% { box-shadow: 0 0 0 14px rgba(100, 100, 100, 0); }
663 }
664 @keyframes darkify_attention_leap {
665 0%, 55%, 100% { transform: translateY(0); }
666 30% { transform: translateY(-14px); }
667 45% { transform: translateY(-8px); }
668 }
669 @keyframes darkify_attention_swing {
670 0%, 100% { transform: rotate(0deg); transform-origin: center bottom; }
671 20% { transform: rotate(-9deg); transform-origin: center bottom; }
672 40% { transform: rotate(7deg); transform-origin: center bottom; }
673 60% { transform: rotate(-5deg); transform-origin: center bottom; }
674 80% { transform: rotate(3deg); transform-origin: center bottom; }
675 }
676 @keyframes darkify_attention_drift {
677 0%, 100% { transform: translateY(0); }
678 50% { transform: translateY(-8px); }
679 }
680 @keyframes darkify_attention_nudge {
681 0%, 65%, 100% { transform: translateX(0); }
682 10% { transform: translateX(-6px); }
683 20% { transform: translateX(6px); }
684 30% { transform: translateX(-4px); }
685 40% { transform: translateX(4px); }
686 50% { transform: translateX(-2px); }
687 57% { transform: translateX(2px); }
688 }
689 .darkify_switch.darkify_attention_pulse {
690 animation: darkify_attention_pulse 2s ease-in-out 2s infinite;
691 }
692 .darkify_switch.darkify_attention_radiance {
693 animation: darkify_attention_radiance 2s ease-in-out 2s infinite;
694 }
695 .darkify_switch.darkify_attention_leap {
696 animation: darkify_attention_leap 2.5s ease-in-out 2s infinite;
697 }
698 .darkify_switch.darkify_attention_swing {
699 animation: darkify_attention_swing 1.6s ease-in-out 2s infinite;
700 }
701 .darkify_switch.darkify_attention_drift {
702 animation: darkify_attention_drift 3s ease-in-out 2s infinite;
703 }
704 .darkify_switch.darkify_attention_nudge {
705 animation: darkify_attention_nudge 2.5s ease-in-out 2s infinite;
706 }
707 .darkify_switch.darkify_attention_pulse:hover,
708 .darkify_switch.darkify_attention_radiance:hover,
709 .darkify_switch.darkify_attention_leap:hover,
710 .darkify_switch.darkify_attention_swing:hover,
711 .darkify_switch.darkify_attention_drift:hover,
712 .darkify_switch.darkify_attention_nudge:hover {
713 animation-play-state: paused;
714 }
715 /*
716 * Transition suppression for the duration of an engine pass.
717 *
718 * The engine classifies an element from its computed colours, and a colour
719 * mid-transition computes to an interpolated value that belongs to neither the
720 * start nor the end state — so a pass that runs while the page is animating
721 * reads colours the design never actually paints. Suppressing transitions for
722 * the length of the pass makes every read a settled one.
723 *
724 * This replaces an inline `transition-property: none !important` that was
725 * written to, and then removed from, every element individually. Writing a
726 * style and then reading a computed style off the same element forces a
727 * synchronous style recalculation, so that pattern cost one full recalc per
728 * element; as one class on the root it costs one invalidation per pass.
729 *
730 * `!important` is warranted here and is the reason the declaration can stay a
731 * single rule: it has to beat inline transitions written by builders and
732 * animation libraries, which is precisely the case it exists to neutralise. It
733 * is present only while a pass is running — never in the page's resting state.
734 */
735 /*
736 * The switcher is deliberately outside this suppression, and leaving it in was
737 * a real bug: it silently removed the toggle's animation.
738 *
739 * The switcher is the one animated thing on the page that the engine does not
740 * manage — it never receives `darkify_processed`, its colours are never read to
741 * classify it, and its whole visual job is to animate between the two states.
742 * Suppressing transitions on it therefore protects nothing and costs the
743 * feature.
744 *
745 * The damage is not obvious from reading the rule, because the class is added
746 * and removed inside a single synchronous task, so it is never painted. What
747 * matters is that the pass calls `getComputedStyle` thousands of times while
748 * the class is on, and every one of those forces a style recalculation. A
749 * recalculation that sees `transition-property: none` *cancels the transitions
750 * already running* — and the switcher's transitions started moments earlier,
751 * when the state class flipped. Removing the class afterwards does not revive
752 * them; the values have already been committed to their end state. Measured on
753 * the stress page: 17 transitions created on `d`, `opacity` and `transform`,
754 * all with `currentTime` still 0, gone by the next frame — the toggle snapped
755 * instead of animating.
756 *
757 * `.darkify_ignore` is excluded for the same reason it is excluded from every
758 * other rule in this file: it marks a subtree the plugin has been told to keep
759 * its hands off, and cancelling its animations is exactly the interference the
760 * marker exists to prevent.
761 *
762 * This costs nothing. The exclusion is evaluated only while a pass is running,
763 * and it removes work rather than adding it — the excluded subtrees are the
764 * ones the engine was never going to read.
765 */
766 html.darkify_suspend_transitions,
767 html.darkify_suspend_transitions
768 *:not(
769 .darkify_switch,
770 .darkify_switch *,
771 .darkify_ignore,
772 .darkify_ignore *
773 ) {
774 transition-property: none !important;
775 }
776
777 /*
778 * The same suppression, scoped to a single element.
779 *
780 * The rule above is correct for the two passes that read the whole document —
781 * the first walk and the dark-mode state sweep — because at those moments the
782 * page is either not yet interactive or is being repainted wholesale anyway.
783 * It is wrong for the incremental passes, and that is what this rule exists to
784 * fix. Those run whenever any element's class list changes, which on a real
785 * site is constantly: a menu opening, a slider advancing, a scroll-state class,
786 * a builder's hover class. Suppressing document-wide for one of those cancels
787 * every transition running anywhere on the page — including on elements the
788 * pass never looked at — so hover effects, dropdowns and reveal animations
789 * snapped to their end state instead of easing to it. The elements were never
790 * being read; they were collateral.
791 *
792 * Scoping it to the element under the reader keeps the read settled and leaves
793 * the rest of the page animating. `transition-property` is not inherited, so
794 * this cancels the element's own transitions and nothing below it.
795 */
796 .darkify_no_transition:not(
797 .darkify_switch,
798 .darkify_switch *,
799 .darkify_ignore,
800 .darkify_ignore *
801 ) {
802 transition-property: none !important;
803 }
804