| 1 |
/** |
| 2 |
* MLS Import Design Settings — two-level vertical menu layout. |
| 3 |
* |
| 4 |
* Left rail lists every screen: top-level items, and — for a section that has |
| 5 |
* subtabs (e.g. Property Page) — its subtabs indented directly underneath it. |
| 6 |
* The right panel shows only the selected screen's fields. |
| 7 |
*/ |
| 8 |
|
| 9 |
/* Two-pane shell: left rail + right panel side by side, equal height. */ |
| 10 |
.mlsimport-settings-tabs { |
| 11 |
display: flex; |
| 12 |
align-items: stretch; |
| 13 |
gap: 0; |
| 14 |
} |
| 15 |
|
| 16 |
/* Left rail — fixed 210px column holding the stacked menu items. */ |
| 17 |
.mlsimport-settings-tabs__menu { |
| 18 |
flex: 0 0 210px; |
| 19 |
display: flex; |
| 20 |
flex-direction: column; |
| 21 |
gap: 2px; |
| 22 |
border-right: 1px solid var(--border-color, rgba(28, 25, 23, 0.12)); |
| 23 |
padding-right: 8px; |
| 24 |
} |
| 25 |
|
| 26 |
.mlsimport-settings-tabs__group { |
| 27 |
display: flex; |
| 28 |
flex-direction: column; |
| 29 |
gap: 2px; |
| 30 |
} |
| 31 |
|
| 32 |
/* Base menu button (shared by top-level items, parents and subtabs). */ |
| 33 |
.mlsimport-settings-tabs__item { |
| 34 |
display: block; |
| 35 |
width: 100%; |
| 36 |
box-sizing: border-box; |
| 37 |
padding: 8px 12px; |
| 38 |
background: none; |
| 39 |
border: none; |
| 40 |
border-radius: 4px; |
| 41 |
text-align: left; |
| 42 |
font-size: 13px; |
| 43 |
color: var(--text-primary, #1c1917); |
| 44 |
cursor: pointer; |
| 45 |
} |
| 46 |
|
| 47 |
.mlsimport-settings-tabs__item:hover { |
| 48 |
background: var(--background-soft, #f3efe7); |
| 49 |
} |
| 50 |
|
| 51 |
.mlsimport-settings-tabs__item:focus-visible { |
| 52 |
outline: 2px solid var(--primary-color, #1c1917); |
| 53 |
outline-offset: -2px; |
| 54 |
} |
| 55 |
|
| 56 |
/* Selected screen. One active-state colour plugin-wide: the near-black |
| 57 |
--primary-color fill, the same as the selected tab on |
| 58 |
admin.php?page=mlsimport_plugin_options. This was the pastel --accent-soft, |
| 59 |
which is the badge/checkbox accent, not an active state. */ |
| 60 |
.mlsimport-settings-tabs__item.is-active { |
| 61 |
background: var(--primary-color, #1c1917); |
| 62 |
color: #ffffff; |
| 63 |
font-weight: 600; |
| 64 |
} |
| 65 |
|
| 66 |
.mlsimport-settings-tabs__item.is-active:hover { |
| 67 |
background: var(--primary-hover, #33302b); |
| 68 |
color: #ffffff; |
| 69 |
} |
| 70 |
|
| 71 |
/* Section header for a group of subtabs — reads as the parent of the items below. */ |
| 72 |
.mlsimport-settings-tabs__item.is-parent { |
| 73 |
color: var(--text-secondary, #6b6358); |
| 74 |
font-weight: 600; |
| 75 |
} |
| 76 |
|
| 77 |
/* Subtab: indented under its parent, with a rail marking the nesting. */ |
| 78 |
.mlsimport-settings-tabs__item.is-child { |
| 79 |
margin-left: 12px; |
| 80 |
width: calc( 100% - 12px ); |
| 81 |
padding-left: 14px; |
| 82 |
border-left: 2px solid var(--border-color, rgba(28, 25, 23, 0.12)); |
| 83 |
border-radius: 0 4px 4px 0; |
| 84 |
} |
| 85 |
|
| 86 |
.mlsimport-settings-tabs__item.is-child.is-active { |
| 87 |
border-left-color: var(--primary-color, #1c1917); |
| 88 |
} |
| 89 |
|
| 90 |
/* Right panel — fills remaining width and renders the active screen's fields. */ |
| 91 |
.mlsimport-settings-tabs__panel { |
| 92 |
flex: 1 1 auto; |
| 93 |
min-width: 0; |
| 94 |
padding: 8px 4px 4px 20px; |
| 95 |
min-height: 320px; |
| 96 |
} |
| 97 |
|
| 98 |
/* Section title (e.g. "Social & Contact") — space it off from the fields below. */ |
| 99 |
#mlsimport-standalone-app .mlsimport-settings-tabs__panel > .components-heading { |
| 100 |
margin-bottom: 15px; |
| 101 |
} |
| 102 |
|
| 103 |
/* WP component input labels (TextControl, SelectControl, …) default to ALL-CAPS. |
| 104 |
Render them in normal sentence case to match the field text and the button-group |
| 105 |
headings (e.g. "Cards per row"), so no label shouts. */ |
| 106 |
#mlsimport-standalone-app .components-base-control__label, |
| 107 |
#mlsimport-standalone-app .components-input-control__label { |
| 108 |
text-transform: none; |
| 109 |
letter-spacing: normal; |
| 110 |
} |
| 111 |
|
| 112 |
/* =========================================================================== |
| 113 |
Match the shared wp-admin "2025" look (the field_options tab on |
| 114 |
admin.php?page=mlsimport_plugin_options). This React page is built from |
| 115 |
@wordpress/components, whose default chrome differs from the plugin's own |
| 116 |
settings screens. The rules below re-skin those components — inputs, labels, |
| 117 |
help text and buttons — to the SAME tokens defined in mlsimport-admin.css |
| 118 |
(.mlsimport-2025-input, .mlsimport-label, .button.mlsimport_button), so both |
| 119 |
surfaces read as one design system. Scoped to #mlsimport-standalone-app; the |
| 120 |
#id selector out-specifies wp-components without needing !important. |
| 121 |
=========================================================================== */ |
| 122 |
|
| 123 |
/* Text / number / email / textarea / select — bordered, rounded, soft shadow, |
| 124 |
mirroring input.mlsimport-2025-input and select.mlsimport-2025-select. */ |
| 125 |
#mlsimport-standalone-app .components-text-control__input, |
| 126 |
#mlsimport-standalone-app .components-textarea-control__input, |
| 127 |
#mlsimport-standalone-app .components-select-control__input { |
| 128 |
padding: 5px 12px; |
| 129 |
min-height: 40px; |
| 130 |
box-sizing: border-box; |
| 131 |
background: #ffffff; |
| 132 |
color: var(--text-primary, #1c1917); |
| 133 |
border: 1px solid rgba(28, 25, 23, 0.18); |
| 134 |
border-radius: 8px; |
| 135 |
box-shadow: 0px 1px 2px rgba( 0, 0, 0, 0.08 ); |
| 136 |
} |
| 137 |
|
| 138 |
#mlsimport-standalone-app .components-textarea-control__input { |
| 139 |
min-height: 0; |
| 140 |
} |
| 141 |
|
| 142 |
/* SelectControl is special: unlike TextControl (a plain <input> that carries its |
| 143 |
own border), WP's SelectControl draws the *visible* border on a separate |
| 144 |
overlay element, .components-input-control__backdrop — a 1px solid #949494 box |
| 145 |
that sits on top of the <select>. So the border rules above only recolored the |
| 146 |
hidden inner <select> border; the backdrop kept painting the darker WP default |
| 147 |
over it. Style the backdrop itself to the 2025 token (rgba(28,25,23,0.18), 8px |
| 148 |
radius) so the select border matches the text inputs and the field_options |
| 149 |
selects. The soft drop shadow lives on the inner <select>, re-asserted with |
| 150 |
!important because the SelectControl emotion class forces box-shadow: none. */ |
| 151 |
#mlsimport-standalone-app .components-input-control__backdrop { |
| 152 |
border-color: rgba(28, 25, 23, 0.18) !important; |
| 153 |
border-radius: 8px !important; |
| 154 |
} |
| 155 |
|
| 156 |
#mlsimport-standalone-app .components-select-control__input { |
| 157 |
box-shadow: 0px 1px 2px rgba( 28, 25, 23, 0.08 ) !important; |
| 158 |
} |
| 159 |
|
| 160 |
/* Focus: an actual border in --primary-color, no glow — the same focus |
| 161 |
affordance the plugin's own fields got in the Tools-tab pass. It used to be |
| 162 |
an --accent-color ring; accent is reserved for badges and checked checkboxes. |
| 163 |
The SelectControl backdrop is named too, since that overlay (not the inner |
| 164 |
<select>) is what paints a select's visible border. */ |
| 165 |
#mlsimport-standalone-app .components-text-control__input:focus, |
| 166 |
#mlsimport-standalone-app .components-textarea-control__input:focus, |
| 167 |
#mlsimport-standalone-app .components-select-control__input:focus { |
| 168 |
border-color: var(--primary-color, #1c1917); |
| 169 |
box-shadow: 0px 1px 2px rgba( 0, 0, 0, 0.08 ); |
| 170 |
outline: none; |
| 171 |
} |
| 172 |
|
| 173 |
#mlsimport-standalone-app .components-input-control__input:focus ~ .components-input-control__backdrop, |
| 174 |
#mlsimport-standalone-app .components-select-control__input:focus ~ .components-input-control__backdrop { |
| 175 |
border-color: var(--primary-color, #1c1917) !important; |
| 176 |
} |
| 177 |
|
| 178 |
/* Field labels — block, 14px, medium weight, dark text (matches .mlsimport-label |
| 179 |
on the field_options tab). Covers BOTH label classes: TextControl/TextareaControl |
| 180 |
use .components-base-control__label, while SelectControl renders its label as an |
| 181 |
InputControl label (.components-input-control__label). WP components render both at |
| 182 |
11px by default — smaller than the 12px help text, which reads as broken — so the |
| 183 |
font-size is forced up with !important to beat the emotion-hashed default. */ |
| 184 |
#mlsimport-standalone-app .components-base-control__label, |
| 185 |
#mlsimport-standalone-app .components-input-control__label { |
| 186 |
display: block; |
| 187 |
margin-bottom: 4px; |
| 188 |
font-size: 14px !important; |
| 189 |
font-weight: 500; |
| 190 |
color: var(--text-primary, #1c1917); |
| 191 |
} |
| 192 |
|
| 193 |
/* Help / explanation text under a field — muted (matches .mls_explanations). */ |
| 194 |
#mlsimport-standalone-app .components-base-control__help { |
| 195 |
color: var(--text-secondary, #6b6358); |
| 196 |
font-size: 12px; |
| 197 |
} |
| 198 |
|
| 199 |
/* --- Buttons --------------------------------------------------------------- |
| 200 |
Primary buttons take the solid dark fill of .button.mlsimport_button; the |
| 201 |
bottom "Save changes" button (tagged .mlsimport-save-button) takes the green |
| 202 |
save fill (.button.mlsimport_button.save_data), exactly like the Save |
| 203 |
Changes button on the field_options tab. Secondary/tertiary buttons become a |
| 204 |
neutral bordered control on the same pill-radius token. */ |
| 205 |
#mlsimport-standalone-app .components-button.is-primary { |
| 206 |
height: auto; |
| 207 |
padding: 7px 30px; |
| 208 |
color: #ffffff; |
| 209 |
background: var(--primary-color, #1c1917); |
| 210 |
border: 1px solid var(--primary-color, #1c1917); |
| 211 |
border-radius: 999px; |
| 212 |
box-shadow: rgba( 28, 25, 23, 0.08 ) 0px 1px 2px 0px, rgba( 28, 25, 23, 0.08 ) 0px 0px 0px 1px inset, rgba( 255, 255, 255, 0.06 ) 0px 2px 0px 0px inset; |
| 213 |
} |
| 214 |
|
| 215 |
#mlsimport-standalone-app .components-button.is-primary:hover:not( :disabled ), |
| 216 |
#mlsimport-standalone-app .components-button.is-primary:focus:not( :disabled ) { |
| 217 |
color: #ffffff; |
| 218 |
background: var(--primary-hover, #33302b); |
| 219 |
border: 1px solid var(--primary-hover, #33302b); |
| 220 |
box-shadow: 0 10px 24px -10px rgba( 0, 0, 0, .45 ); |
| 221 |
} |
| 222 |
|
| 223 |
/* Save changes — the same pastel mint save pill the rest of the plugin uses |
| 224 |
(.button.mlsimport_button.save_data in mlsimport-admin.css): --success-soft |
| 225 |
fill with --success-deep text. This button was a solid saturated |
| 226 |
--success-color green, a fill no other MLSImport screen shows. The 57px |
| 227 |
min-height goes with it, so Save stands at the same height as every other |
| 228 |
button instead of towering over the panel it closes. */ |
| 229 |
#mlsimport-standalone-app .components-button.is-primary.mlsimport-save-button { |
| 230 |
padding: 9px 24px; |
| 231 |
background: var(--success-soft, #b8e6cc); |
| 232 |
border: 1px solid var(--success-soft, #b8e6cc); |
| 233 |
color: var(--success-deep, #1c5c3a); |
| 234 |
box-shadow: 0px 1px 2px rgba( 0, 0, 0, 0.06 ); |
| 235 |
} |
| 236 |
|
| 237 |
#mlsimport-standalone-app .components-button.is-primary.mlsimport-save-button:hover:not( :disabled ), |
| 238 |
#mlsimport-standalone-app .components-button.is-primary.mlsimport-save-button:focus:not( :disabled ) { |
| 239 |
background: #a5dfc0; |
| 240 |
border: 1px solid #a5dfc0; |
| 241 |
color: var(--success-deep, #1c5c3a); |
| 242 |
box-shadow: 0 8px 20px -10px rgba( 28, 92, 58, 0.5 ); |
| 243 |
} |
| 244 |
|
| 245 |
/* Secondary / tertiary — white bordered button on the same rounded token. */ |
| 246 |
#mlsimport-standalone-app .components-button.is-secondary, |
| 247 |
#mlsimport-standalone-app .components-button.is-tertiary { |
| 248 |
height: auto; |
| 249 |
padding: 7px 18px; |
| 250 |
background: #ffffff; |
| 251 |
color: var(--text-primary, #1c1917); |
| 252 |
border: 1px solid rgba(28, 25, 23, 0.18); |
| 253 |
border-radius: 999px; |
| 254 |
box-shadow: 0px 1px 2px rgba( 28, 25, 23, 0.08 ); |
| 255 |
} |
| 256 |
|
| 257 |
#mlsimport-standalone-app .components-button.is-secondary:hover:not( :disabled ), |
| 258 |
#mlsimport-standalone-app .components-button.is-tertiary:hover:not( :disabled ) { |
| 259 |
background: var(--background-soft, #f3efe7); |
| 260 |
color: var(--text-primary, #1c1917); |
| 261 |
border-color: rgba(28, 25, 23, 0.18); |
| 262 |
} |
| 263 |
|
| 264 |
/* Colors screen — the Main Color control is wp-admin's own Iris picker |
| 265 |
(button.wp-color-result), which core renders as a square grey .button with a |
| 266 |
4px radius. It sat next to our 8px rounded fields as the one un-restyled |
| 267 |
control on the page. Give it the same 40px height, border and radius as a |
| 268 |
text field; the inline background-color core sets on the button is the swatch, |
| 269 |
so only the border, radius and the text half are touched. */ |
| 270 |
#mlsimport-standalone-app .wp-picker-container .wp-color-result.button { |
| 271 |
height: 40px; |
| 272 |
margin: 0; |
| 273 |
border: 1px solid rgba(28, 25, 23, 0.18); |
| 274 |
border-radius: 8px; |
| 275 |
box-shadow: 0px 1px 2px rgba( 0, 0, 0, 0.08 ); |
| 276 |
} |
| 277 |
|
| 278 |
#mlsimport-standalone-app .wp-picker-container .wp-color-result.button:focus, |
| 279 |
#mlsimport-standalone-app .wp-picker-container .wp-color-result.button:hover { |
| 280 |
border-color: var(--primary-color, #1c1917); |
| 281 |
box-shadow: 0px 1px 2px rgba( 0, 0, 0, 0.08 ); |
| 282 |
} |
| 283 |
|
| 284 |
#mlsimport-standalone-app .wp-picker-container .wp-color-result-text { |
| 285 |
background: #ffffff; |
| 286 |
color: var(--text-primary, #1c1917); |
| 287 |
border-left: 1px solid rgba(28, 25, 23, 0.18); |
| 288 |
border-radius: 0 7px 7px 0; |
| 289 |
line-height: 38px; |
| 290 |
} |
| 291 |
|
| 292 |
/* --- Focus / accent --------------------------------------------------------- |
| 293 |
The selected option pill was ringed in WP admin blue (#3858e9): every |
| 294 |
@wordpress/components control paints its focus ring, checkbox fill and |
| 295 |
toggle from --wp-components-color-accent / --wp-admin-theme-color, neither |
| 296 |
of which our tokens touched. Repoint both at --primary-color at the app |
| 297 |
root, so anything core draws in "the accent" adopts the plugin's near-black |
| 298 |
instead of leaking WP blue into a screen that has none. */ |
| 299 |
#mlsimport-standalone-app { |
| 300 |
--wp-admin-theme-color: var(--primary-color, #1c1917); |
| 301 |
--wp-admin-theme-color-darker-10: var(--primary-hover, #33302b); |
| 302 |
--wp-admin-theme-color-darker-20: var(--primary-hover, #33302b); |
| 303 |
--wp-components-color-accent: var(--primary-color, #1c1917); |
| 304 |
--wp-components-color-accent-darker-10: var(--primary-hover, #33302b); |
| 305 |
--wp-components-color-accent-darker-20: var(--primary-hover, #33302b); |
| 306 |
} |
| 307 |
|
| 308 |
/* Keyboard focus on a button: a near-black ring OUTSIDE the pill, so it reads |
| 309 |
on the dark primary fill as well as on the white secondary one. Plain :focus |
| 310 |
is left alone — a mouse click on an option pill should not leave a ring |
| 311 |
behind, which is what made the selected pill look permanently outlined. */ |
| 312 |
#mlsimport-standalone-app .components-button:focus:not( :disabled ) { |
| 313 |
outline: 2px solid transparent; |
| 314 |
outline-offset: 0; |
| 315 |
} |
| 316 |
|
| 317 |
#mlsimport-standalone-app .components-button:focus-visible:not( :disabled ) { |
| 318 |
outline: 2px solid var(--primary-color, #1c1917); |
| 319 |
outline-offset: 2px; |
| 320 |
} |
| 321 |
|
| 322 |
/* Core paints an accent ring as a box-shadow on a focused secondary button, so |
| 323 |
clicking an option pill left a ring on it. Hold the resting shadow on plain |
| 324 |
:focus and let the outline above carry keyboard focus instead. */ |
| 325 |
#mlsimport-standalone-app .components-button.is-secondary:focus:not( :disabled ), |
| 326 |
#mlsimport-standalone-app .components-button.is-tertiary:focus:not( :disabled ) { |
| 327 |
box-shadow: 0px 1px 2px rgba( 28, 25, 23, 0.08 ); |
| 328 |
} |
| 329 |
|
| 330 |
/* =========================================================================== |
| 331 |
Mobile layout |
| 332 |
|
| 333 |
WordPress collapses its admin navigation at 782px. At that width the fixed |
| 334 |
210px settings rail and the field panel no longer fit side by side: the panel |
| 335 |
is squeezed into a narrow strip and the full-height card can cover the Save |
| 336 |
action below it. Stack the same two public controls in document order so the |
| 337 |
menu, active panel, and Save button each own a separate vertical region. |
| 338 |
=========================================================================== */ |
| 339 |
@media screen and ( max-width: 782px ) { |
| 340 |
.mlsimport-settings-tabs { |
| 341 |
flex-direction: column; |
| 342 |
align-items: stretch; |
| 343 |
} |
| 344 |
|
| 345 |
.mlsimport-settings-tabs__menu { |
| 346 |
flex: 0 1 auto; |
| 347 |
width: 100%; |
| 348 |
box-sizing: border-box; |
| 349 |
padding: 0 0 12px; |
| 350 |
margin: 0 0 12px; |
| 351 |
border-right: 0; |
| 352 |
border-bottom: 1px solid var(--border-color, rgba(28, 25, 23, 0.12)); |
| 353 |
} |
| 354 |
|
| 355 |
.mlsimport-settings-tabs__panel { |
| 356 |
width: 100%; |
| 357 |
box-sizing: border-box; |
| 358 |
min-height: 0; |
| 359 |
padding: 8px 4px 4px; |
| 360 |
} |
| 361 |
} |
| 362 |
|