PluginProbe
Search Atlas SEO – OTTO AI SEO Automation for WordPress / 2.7.1
Search Atlas SEO – OTTO AI SEO Automation for WordPress v2.7.1
2.7.1 2.7.2 2.7.0 2.6.26 2.6.25 2.6.24 2.6.23 2.6.22 2.6.21 2.6.20 2.6.19 2.6.18 2.6.17 2.6.16 2.6.15 2.6.14 2.6.13 2.6.12 2.6.11 2.6.10 2.6.9 2.6.8 2.6.7 2.6.6 2.6.5 All 141 releases
← All changes | admin/css/metasync-dashboard.css +320 -63 2.6.8 → 2.7.1 View file →
@@ -9,9 +9,11 @@
9 9 [data-theme="dark"] {
10 10 --dashboard-bg: #0f1419;
11 11 --dashboard-card-bg: #1a1f26;
12 12 --dashboard-card-hover: #222831;
13 + --dashboard-input-bg: #22272e;
13 14 --dashboard-text-primary: #ffffff;
15 + --dashboard-text: #ffffff;
14 16 --dashboard-text-secondary: #9ca3af;
15 17 --dashboard-accent: #3b82f6;
16 18 --dashboard-accent-hover: #2563eb;
17 19 --dashboard-success: #10b981;
@@ -28,9 +30,11 @@
28 30 [data-theme="light"] {
29 31 --dashboard-bg: #f8f9fa;
30 32 --dashboard-card-bg: #ffffff;
31 33 --dashboard-card-hover: #f1f3f5;
34 + --dashboard-input-bg: #ffffff;
32 35 --dashboard-text-primary: #1a1f26;
36 + --dashboard-text: #1a1f26;
33 37 --dashboard-text-secondary: #6b7280;
34 38 --dashboard-accent: #3b82f6;
35 39 --dashboard-accent-hover: #2563eb;
36 40 --dashboard-success: #10b981;
@@ -123,8 +127,19 @@
123 127 border-left-color: var(--dashboard-error) !important;
124 128 background: rgba(239, 68, 68, 0.15) !important;
125 129 }
126 130
131 +/* Specific warning notice styling ONLY in plugin.
132 + Without this, warning notices fell through to the base .notice rule above
133 + (blue border-left, plain card background) because that rule is !important
134 + and the .notice-warning colours defined further down this file are not —
135 + !important always wins regardless of source order, so the warning never
136 + actually rendered yellow/amber. Mirrors the .notice-error override above. */
137 +.metasync-dashboard-wrap .notice.notice-warning {
138 + border-left-color: var(--dashboard-warning) !important;
139 + background: rgba(245, 158, 11, 0.15) !important;
140 +}
141 +
127 142 /* License mismatch notice specific styling ONLY in plugin */
128 143 .metasync-dashboard-wrap .notice:has(.dashicons-warning):before,
129 144 .metasync-dashboard-wrap .notice[class*="license"]:before,
130 145 .metasync-dashboard-wrap .notice[class*="mismatch"]:before {
@@ -283,8 +298,15 @@
283 298 .metasync-header[data-current-theme="dark"] .metasync-logo-light {
284 299 display: none;
285 300 }
286 301
302 +/* Light theme must explicitly show the light logo: its base state is
303 + display:none, and hiding the dark logo alone would leave no logo visible. */
304 +[data-theme="light"] .metasync-logo-light,
305 +.metasync-header[data-current-theme="light"] .metasync-logo-light {
306 + display: block;
307 +}
308 +
287 309 /* Default (non-whitelabel) SA logo: invert on light theme so the white asset
288 310 stays visible against a light background. Dark theme keeps the original. */
289 311 [data-theme="light"] .metasync-logo-default,
290 312 .metasync-header[data-current-theme="light"] .metasync-logo-default {
@@ -558,9 +580,10 @@
558 580 .metasync-dashboard-wrap .form-table {
559 581 background: transparent;
560 582 border: none;
561 583 border-collapse: separate;
562 - border-spacing: 0;
584 + /* Vertical spacing between each settings row (tr); horizontal stays 0 so th/td join */
585 + border-spacing: 0 12px;
563 586 width: 100%;
564 587 }
565 588
566 589 .metasync-dashboard-wrap .form-table th {
@@ -584,24 +607,9 @@
584 607 padding: 16px 20px;
585 608 vertical-align: top;
586 609 }
587 610
588 -.metasync-dashboard-wrap .form-table tr {
589 - margin-bottom: 16px;
590 -}
591 -
592 -.metasync-dashboard-wrap .form-table tr:not(:last-child) th,
593 -.metasync-dashboard-wrap .form-table tr:not(:last-child) td {
594 - border-bottom: none;
595 -}
596 -
597 -/* Simple, clean spacing between form table rows */
598 -.metasync-dashboard-wrap .form-table tr + tr th,
599 -.metasync-dashboard-wrap .form-table tr + tr td {
600 - padding-top: 24px;
601 -}
602 -
603 -/* Ensure proper internal padding for all cells */
611 +/* Each row is a self-contained card; vertical gaps come from border-spacing above */
604 612 .metasync-dashboard-wrap .form-table th,
605 613 .metasync-dashboard-wrap .form-table td {
606 614 padding: 16px 12px;
607 615 }
@@ -1014,15 +1022,62 @@
1014 1022 gap: 8px;
1015 1023 font-size: 14px;
1016 1024 }
1017 1025
1018 -.metasync-dashboard-wrap .button:hover,
1019 -.metasync-dashboard-wrap .button-primary:hover {
1026 +.metasync-dashboard-wrap .button .dashicons,
1027 +.metasync-dashboard-wrap .button-primary .dashicons,
1028 +.metasync-dashboard-wrap .button-secondary .dashicons {
1029 + font-size: 15px !important;
1030 + width: 15px !important;
1031 + height: 15px !important;
1032 + line-height: 15px !important;
1033 + margin: 0 !important;
1034 + vertical-align: middle;
1035 +}
1036 +
1037 +.metasync-dashboard-wrap .button:hover:not(:disabled):not([disabled]),
1038 +.metasync-dashboard-wrap .button-primary:hover:not(:disabled):not([disabled]) {
1020 1039 background: var(--dashboard-gradient-accent);
1021 1040 transform: translateY(-1px);
1022 1041 box-shadow: var(--dashboard-shadow);
1023 1042 }
1024 1043
1044 +/* Disabled state — needed because the base .button-primary rule keeps the
1045 + full gradient even when prop('disabled', true) is set. Without this,
1046 + the Sync Now button stays blue/purple while the cooldown countdown is
1047 + active (QA report).
1048 +
1049 + The .is-throttled class is the primary driver for the Sync Now cooldown
1050 + visual because earlier code in the AJAX callback chain calls
1051 + .prop('disabled', false) before our refresh runs, and in some browsers
1052 + that ordering can leave the disabled attribute off even though we set
1053 + it again afterwards. The class-based path doesn't depend on the
1054 + disabled attribute reaching the DOM and survives any prop juggling. */
1055 +.metasync-dashboard-wrap .button:disabled,
1056 +.metasync-dashboard-wrap .button-primary:disabled,
1057 +.metasync-dashboard-wrap .button-secondary:disabled,
1058 +.metasync-dashboard-wrap .button[disabled],
1059 +.metasync-dashboard-wrap .button-primary[disabled],
1060 +.metasync-dashboard-wrap .button-secondary[disabled],
1061 +.metasync-dashboard-wrap .button.is-throttled,
1062 +.metasync-dashboard-wrap .button-primary.is-throttled,
1063 +.metasync-dashboard-wrap .button-secondary.is-throttled {
1064 + /* Replace the blue/purple gradient with a solid grey. The base rule sets
1065 + `background: var(--dashboard-gradient-primary)`, so opacity + grayscale
1066 + alone left the button a dimmed blue (QA: "still blue on Elementor").
1067 + background/filter/pointer-events carry !important so a page-builder's
1068 + admin stylesheet (Elementor ships more than Divi) can't override them. */
1069 + background: #d5d7da !important;
1070 + background-image: none !important;
1071 + color: #6b7280 !important;
1072 + opacity: 0.7 !important;
1073 + cursor: not-allowed !important;
1074 + transform: none !important;
1075 + box-shadow: none !important;
1076 + filter: grayscale(100%) !important;
1077 + pointer-events: none !important;
1078 +}
1079 +
1025 1080 .metasync-dashboard-wrap .button-secondary {
1026 1081 background: transparent;
1027 1082 border: 1px solid var(--dashboard-border);
1028 1083 color: var(--dashboard-text-secondary);
@@ -1299,9 +1354,13 @@
1299 1354 border-color: var(--dashboard-error);
1300 1355 /* Removed translateY animation - was too distracting */
1301 1356 }
1302 1357
1303 -/* Connect Status Messages - Dashboard Style */
1358 +/* Connect Status Messages - Dashboard Style
1359 + The box holds two block children — .metasync-sa-connect-status-content and
1360 + .metasync-sa-connect-actions — so it must stack. As a row, the actions block
1361 + sized to its buttons while the content block (flex: 1, so flex-basis: 0) was
1362 + squeezed into whatever was left, wrapping the message one word per line. */
1304 1363 .metasync-dashboard-wrap .metasync-sa-connect-status,
1305 1364 .metasync-dashboard-wrap #sa-connect-status-message {
1306 1365 margin-top: 16px;
1307 1366 padding: 16px 20px;
@@ -1306,9 +1365,10 @@
1306 1365 margin-top: 16px;
1307 1366 padding: 16px 20px;
1308 1367 border-radius: 12px;
1309 1368 display: flex;
1310 - align-items: flex-start;
1369 + flex-direction: column;
1370 + align-items: stretch;
1311 1371 gap: 12px;
1312 1372 font-weight: 500;
1313 1373 /* Removed slideInNotice animation - was too distracting */
1314 1374 backdrop-filter: blur(10px);
@@ -1564,9 +1624,14 @@
1564 1624 }
1565 1625
1566 1626 /* Connect Status Message Content */
1567 1627 .metasync-dashboard-wrap .metasync-sa-connect-status-content {
1568 - flex: 1;
1628 + /* min-width: 0 keeps a long unbroken string (a pasted URL, a UUID) from
1629 + setting the flex item's min-content width and re-inflating the box. */
1630 + flex: 0 0 auto;
1631 + min-width: 0;
1632 + /* Spacing between content and actions is the container's gap now. */
1633 + margin-bottom: 0;
1569 1634 }
1570 1635
1571 1636 .metasync-dashboard-wrap .metasync-sa-connect-status-title {
1572 1637 font-weight: 600;
@@ -1571,11 +1636,15 @@
1571 1636 .metasync-dashboard-wrap .metasync-sa-connect-status-title {
1572 1637 font-weight: 600;
1573 1638 font-size: 15px;
1574 1639 margin-bottom: 8px;
1575 - display: flex;
1576 - align-items: center;
1577 - gap: 8px;
1640 + /* Block, not flex. WordPress core's emoji script rewrites the leading
1641 + emoji into <img class="emoji">; as a flex container that image became a
1642 + flex item of its own and, under align-items: center, floated to the
1643 + vertical middle of a wrapped title. Inline flow keeps it on the first
1644 + line and wraps with the text. The title string already carries the
1645 + separating space, so the old gap is not needed. */
1646 + display: block;
1578 1647 }
1579 1648
1580 1649 .metasync-dashboard-wrap .metasync-sa-connect-status-message {
1581 1650 font-size: 14px;
@@ -1580,14 +1649,14 @@
1580 1649 .metasync-dashboard-wrap .metasync-sa-connect-status-message {
1581 1650 font-size: 14px;
1582 1651 line-height: 1.5;
1583 1652 opacity: 0.9;
1584 - margin-bottom: 12px;
1653 + margin-bottom: 0;
1585 1654 }
1586 1655
1587 1656 /* Existing Connect Actions Container */
1588 1657 .metasync-dashboard-wrap .metasync-sa-connect-actions {
1589 - margin-top: 16px;
1658 + margin-top: 0;
1590 1659 display: flex;
1591 1660 gap: 12px;
1592 1661 flex-wrap: wrap;
1593 1662 align-items: center;
@@ -1664,10 +1733,8 @@
1664 1733
1665 1734 .metasync-dashboard-wrap .metasync-sa-connect-status {
1666 1735 padding: 16px;
1667 1736 margin-top: 12px;
1668 - flex-direction: column;
1669 - align-items: flex-start;
1670 1737 gap: 8px;
1671 1738 }
1672 1739
1673 1740 .metasync-dashboard-wrap .metasync-sa-connect-status-title {
@@ -2419,9 +2486,13 @@
2419 2486 /* Sync Log Header */
2420 2487 .sync-log-header {
2421 2488 display: flex;
2422 2489 justify-content: space-between;
2423 - align-items: flex-start;
2490 + /* Centred rather than flex-start: the title section used to be a two-line
2491 + * block (24px heading + description) that read fine top-aligned, but it is
2492 + * now a single line of copy sitting beside a 34px control row. Top-aligning
2493 + * a one-line block against that row leaves the text visibly high. */
2494 + align-items: center;
2424 2495 margin-bottom: 30px;
2425 2496 gap: 20px;
2426 2497 }
2427 2498
@@ -2428,14 +2499,11 @@
2428 2499 .sync-log-title-section {
2429 2500 flex: 1;
2430 2501 }
2431 2502
2432 -.sync-log-title-section h2 {
2433 - color: var(--dashboard-text-primary);
2434 - margin-bottom: 8px;
2435 - font-size: 24px;
2436 - font-weight: 600;
2437 -}
2503 +/* The card no longer renders an <h2> — the page title and description come
2504 + * from the layout header (render_layout_open), and the card carries only the
2505 + * 90-day retention hint. See admin/class-metasync-admin.php. */
2438 2506
2439 2507 /* Sync Log Filters */
2440 2508 .sync-log-filters {
2441 2509 flex-shrink: 0;
@@ -2441,34 +2509,73 @@
2441 2509 flex-shrink: 0;
2442 2510 display: flex;
2443 2511 align-items: center;
2444 2512 justify-content: flex-end;
2513 + gap: 10px;
2445 2514 }
2446 2515
2447 2516 .sync-filters-form {
2448 - display: grid;
2449 - grid-template-columns: 1fr 1fr;
2517 + display: flex !important;
2518 + flex-direction: row !important;
2519 + flex-wrap: nowrap;
2450 2520 gap: 12px;
2451 2521 align-items: center;
2452 - justify-content: end;
2453 - width: auto;
2454 - min-width: 280px;
2455 2522 }
2456 2523
2457 2524 /* Large screens - optimize filter spacing */
2458 2525 @media (min-width: 1200px) {
2459 2526 .sync-filters-form {
2460 - min-width: 320px;
2461 2527 gap: 16px;
2462 2528 }
2463 -
2529 +
2464 2530 .sync-filter-select {
2465 2531 min-width: 150px;
2466 2532 }
2467 2533 }
2468 2534
2535 +/*
2536 + * Changes Log toolbar — one shared height for the Clear Log button and the two
2537 + * filter selects.
2538 + *
2539 + * The button is styled inline in the renderer (padding:6px 14px, no height) and
2540 + * rendered ~29px, while the selects picked up WordPress core's own
2541 + * `select { min-height: 40px }` (wp-admin forms.css) on top of
2542 + * .sync-filter-select's padding — so the button sat noticeably shorter than the
2543 + * controls beside it.
2544 + *
2545 + * min-height is the load-bearing declaration here: core's min-height:40px beats
2546 + * a plain height:34px no matter how specific the selector, because min-height
2547 + * wins over height by definition. Setting both pins the row at 34px.
2548 + */
2549 +#metasync-clear-sync-log-btn,
2550 +.sync-log-filters .sync-filter-select {
2551 + height: 34px;
2552 + min-height: 34px;
2553 + box-sizing: border-box;
2554 +}
2555 +
2556 +/* Vertical padding is zeroed so the fixed height above is what the row sees;
2557 + * .sync-filter-select's own padding:8px 12px would otherwise fight it. The base
2558 + * padding-right (34px, reserving space for the chevron) is !important there and
2559 + * still applies. */
2560 +.sync-log-filters .sync-filter-select {
2561 + padding-top: 0;
2562 + padding-bottom: 0;
2563 + line-height: 32px;
2564 +}
2565 +
2566 +/* The button keeps its inline padding:6px 14px, which leaves a 20px content box
2567 + * inside the 34px border-box height — too short for a 32px line-height, so the
2568 + * label would sit off-centre. Flex centering makes line-height irrelevant. */
2569 +#metasync-clear-sync-log-btn {
2570 + display: inline-flex;
2571 + align-items: center;
2572 + justify-content: center;
2573 + line-height: 1;
2574 +}
2575 +
2469 2576 .sync-filter-select {
2470 - background: var(--dashboard-card-bg);
2577 + background-color: var(--dashboard-card-bg);
2471 2578 border: 1px solid var(--dashboard-border);
2472 2579 color: var(--dashboard-text-primary);
2473 2580 padding: 8px 12px;
2474 2581 border-radius: 6px;
@@ -2476,16 +2583,16 @@
2476 2583 width: 100%;
2477 2584 min-width: 130px;
2478 2585 transition: all 0.2s ease;
2479 2586 cursor: pointer;
2480 - appearance: none;
2481 - -webkit-appearance: none;
2482 - -moz-appearance: none;
2483 - background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%239ca3af' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6,9 12,15 18,9'%3e%3c/polyline%3e%3c/svg%3e");
2484 - background-repeat: no-repeat;
2485 - background-position: right 8px center;
2486 - background-size: 16px;
2487 - padding-right: 32px;
2587 + appearance: none !important;
2588 + -webkit-appearance: none !important;
2589 + -moz-appearance: none !important;
2590 + background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23d1d5db' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6,9 12,15 18,9'%3e%3c/polyline%3e%3c/svg%3e") !important;
2591 + background-repeat: no-repeat !important;
2592 + background-position: right 10px center !important;
2593 + background-size: 14px !important;
2594 + padding-right: 34px !important;
2488 2595 white-space: nowrap;
2489 2596 box-sizing: border-box;
2490 2597 }
2491 2598
@@ -2511,8 +2618,39 @@
2511 2618 color: var(--dashboard-text-primary);
2512 2619 padding: 8px;
2513 2620 }
2514 2621
2622 +/* Type field dropdown arrow — Local Business Configuration */
2623 +.metasync-type-select-wrap {
2624 + position: relative;
2625 + display: inline-block;
2626 + width: 100%;
2627 + max-width: 400px;
2628 +}
2629 +
2630 +.metasync-type-select-wrap select {
2631 + appearance: none;
2632 + -webkit-appearance: none;
2633 + -moz-appearance: none;
2634 + padding-right: 36px;
2635 + width: 100%;
2636 + cursor: pointer;
2637 +}
2638 +
2639 +.metasync-type-select-wrap::after {
2640 + content: '';
2641 + position: absolute;
2642 + right: 12px;
2643 + top: 50%;
2644 + transform: translateY(-50%);
2645 + width: 16px;
2646 + height: 16px;
2647 + background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%239ca3af' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6,9 12,15 18,9'%3e%3c/polyline%3e%3c/svg%3e");
2648 + background-repeat: no-repeat;
2649 + background-size: contain;
2650 + pointer-events: none;
2651 +}
2652 +
2515 2653 /* Sync Log List */
2516 2654 .sync-log-list {
2517 2655 background: var(--dashboard-card-bg);
2518 2656 border-radius: 12px;
@@ -2628,13 +2766,20 @@
2628 2766 opacity: 0.6;
2629 2767 color: var(--dashboard-text-secondary);
2630 2768 }
2631 2769
2632 -.sync-log-empty h3 {
2770 +/* The empty-state heading is an <h2>: the card's own <h2> is gone, so the
2771 + * layout's <h1> is the only heading above it and an <h3> here would skip a
2772 + * level. Scoped through .metasync-dashboard-wrap to out-specify
2773 + * ".metasync-dashboard-wrap .dashboard-card h2" (0,3,1) above, which would
2774 + * otherwise impose its 1.5rem card-title sizing and flex display on what is
2775 + * a centred empty-state message. Sizing matches the previous <h3>. */
2776 +.metasync-dashboard-wrap .sync-log-empty h2 {
2633 2777 color: var(--dashboard-text-primary);
2634 - margin-bottom: 8px;
2778 + margin: 0 0 8px 0;
2635 2779 font-size: 18px;
2636 2780 font-weight: 600;
2781 + display: block;
2637 2782 }
2638 2783
2639 2784 .sync-log-empty p {
2640 2785 font-size: 14px;
@@ -2664,8 +2809,61 @@
2664 2809 align-items: center;
2665 2810 gap: 8px;
2666 2811 }
2667 2812
2813 +/*
2814 + * Rows-per-page selector on the Changes Log footer.
2815 + *
2816 + * .metasync-per-page-select is emitted by Metasync_Per_Page_Helper::render_selector()
2817 + * on four screens (Redirections, 404 Monitor, Changes Log, Media Library), but
2818 + * only the other three style it. On the Changes Log it fell through to the
2819 + * generic ".metasync-dashboard-wrap select" rule — width:100%, max-width:400px,
2820 + * padding:12px 16px — so a two-digit control rendered ~295px wide and 64px tall
2821 + * next to 34px dashboard controls.
2822 + *
2823 + * Scoped to .sync-log-pagination-info, a Changes Log-only wrapper, rather than
2824 + * to the shared class: the other three screens already size this control via
2825 + * their own rules (".wrap .tablenav select" for Redirections and 404 Monitor,
2826 + * "#metasync-image-library-form .tablenav select" for Media Library), and a
2827 + * shared rule here would be one more thing competing with them. Keeping it
2828 + * page-scoped means those screens are untouched by construction, not by
2829 + * winning a specificity tie.
2830 + *
2831 + * min-height pairs with height for the same reason as the toolbar rule above —
2832 + * core's select{min-height:40px} would otherwise inflate it back to 40px.
2833 + *
2834 + * Sizing only: admin/js/metasync-per-page.js drives behaviour off the element's
2835 + * data-* attributes, which CSS must not disturb.
2836 + */
2837 +.sync-log-pagination-info .metasync-per-page-select {
2838 + height: 34px;
2839 + min-height: 34px;
2840 + line-height: 32px;
2841 + padding: 0 28px 0 10px;
2842 + font-size: 13px;
2843 + width: auto;
2844 + border-radius: 6px;
2845 + box-sizing: border-box;
2846 + vertical-align: middle;
2847 + cursor: pointer;
2848 + appearance: none;
2849 + -webkit-appearance: none;
2850 + -moz-appearance: none;
2851 + background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23d1d5db' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6,9 12,15 18,9'%3e%3c/polyline%3e%3c/svg%3E");
2852 + background-repeat: no-repeat;
2853 + background-position: right 10px center;
2854 + background-size: 14px;
2855 +}
2856 +
2857 +/* Mirrors .sync-filter-select option. The rule above is the first to apply
2858 + * appearance:none to this control, and dark-theme <option> popups need their
2859 + * colours stated explicitly rather than inherited. */
2860 +.sync-log-pagination-info .metasync-per-page-select option {
2861 + background: var(--dashboard-card-bg);
2862 + color: var(--dashboard-text-primary);
2863 + padding: 8px;
2864 +}
2865 +
2668 2866 .sync-pagination-btn {
2669 2867 display: inline-flex;
2670 2868 align-items: center;
2671 2869 justify-content: center;
@@ -2717,16 +2915,16 @@
2717 2915 justify-content: center;
2718 2916 }
2719 2917
2720 2918 .sync-filters-form {
2721 - display: grid;
2722 - grid-template-columns: 1fr 1fr;
2919 + display: flex !important;
2920 + flex-direction: row !important;
2921 + flex-wrap: nowrap;
2723 2922 gap: 10px;
2923 + align-items: center;
2724 2924 justify-content: center;
2725 - min-width: 260px;
2726 - width: auto;
2727 2925 }
2728 -
2926 +
2729 2927 .sync-filter-select {
2730 2928 min-width: 120px;
2731 2929 font-size: 13px;
2732 2930 }
@@ -2758,16 +2956,20 @@
2758 2956 }
2759 2957
2760 2958 @media (max-width: 480px) {
2761 2959 .sync-filters-form {
2762 - display: grid;
2763 - grid-template-columns: 1fr 1fr;
2960 + display: flex !important;
2961 + flex-direction: row !important;
2962 + flex-wrap: nowrap;
2764 2963 gap: 8px;
2765 - min-width: 240px;
2766 2964 width: 100%;
2767 - max-width: 320px;
2768 2965 }
2769 2966
2967 + /* The vertical half of this padding is intentionally overridden by
2968 + * ".sync-log-filters .sync-filter-select" (0,2,0) above, which pins the
2969 + * toolbar row at 34px. Do NOT re-declare padding here under that
2970 + * descendant selector: it would tie on specificity, win on source order,
2971 + * and silently restore the misalignment this rule set exists to avoid. */
2770 2972 .sync-filter-select {
2771 2973 min-width: 110px;
2772 2974 font-size: 13px;
2773 2975 padding: 6px 8px;
@@ -3288,5 +3490,60 @@
3288 3490 font-size: 24px;
3289 3491 width: 24px;
3290 3492 height: 24px;
3291 3493 color: var(--dashboard-text-secondary);
3494 +}
3495 +
3496 +/* Dismiss button on plugin notices.
3497 + The dashboard script appends a .notice-dismiss to every notice inside
3498 + .metasync-dashboard-wrap, but the notice itself was never given a
3499 + positioning context, so WordPress core's `position: absolute` on the
3500 + button resolved against whatever ancestor happened to be positioned
3501 + instead of the notice box — landing the icon mid-text rather than in the
3502 + notice's own top-right corner. Anchor it explicitly to the notice. */
3503 +.metasync-dashboard-wrap .notice {
3504 + position: relative;
3505 +}
3506 +
3507 +.metasync-dashboard-wrap .notice-dismiss {
3508 + position: absolute;
3509 + top: 8px;
3510 + right: 8px;
3511 + width: 28px;
3512 + height: 28px;
3513 + display: flex;
3514 + align-items: center;
3515 + justify-content: center;
3516 +}
3517 +
3518 +/* WordPress core colours the dismiss icon a near-black grey (#1e1e1e), which
3519 + reads fine on the light theme but is effectively invisible against the dark
3520 + theme's card background. Give it a theme-aware colour instead. !important
3521 + because the icon's colour otherwise wins on specificity alone, the same way
3522 + the base .notice rule above needs !important to beat WP core.
3523 + `.metasync-dashboard-wrap[data-theme="dark"]` matches the common case: the
3524 + wrap carries data-theme itself (set server-side on page load). The plain
3525 + `[data-theme="dark"] .metasync-dashboard-wrap` descendant form is kept too,
3526 + since the in-page theme switcher additionally stamps data-theme on <html>
3527 + once the user toggles it, and either could be the one present. */
3528 +.metasync-dashboard-wrap[data-theme="dark"] .notice-dismiss::before,
3529 +[data-theme="dark"] .metasync-dashboard-wrap .notice-dismiss::before {
3530 + color: var(--dashboard-text-secondary) !important;
3531 +}
3532 +
3533 +.metasync-dashboard-wrap[data-theme="dark"] .notice-dismiss:hover::before,
3534 +.metasync-dashboard-wrap[data-theme="dark"] .notice-dismiss:focus::before,
3535 +[data-theme="dark"] .metasync-dashboard-wrap .notice-dismiss:hover::before,
3536 +[data-theme="dark"] .metasync-dashboard-wrap .notice-dismiss:focus::before {
3537 + color: var(--dashboard-text-primary) !important;
3538 +}
3539 +
3540 +/* Remove WordPress footer space on MetaSync admin pages. */
3541 +body:has(.metasync-dashboard-wrap) #wpbody-content,
3542 +body:has(.metasync-otto-debug) #wpbody-content {
3543 + padding-bottom: 0;
3544 +}
3545 +
3546 +body:has(.metasync-dashboard-wrap) #wpfooter,
3547 +body:has(.metasync-otto-debug) #wpfooter {
3548 + display: none;
3292 3549 }