/**
 * search.css
 *
 * All styling for views/search.php — loaded only on the search page (see
 * layouts/head.php's $page === 'search' check). Same palette as
 * listing-detail.css/market-report-listings.php (#12233D text, #DCE1E8
 * borders, #F7F8FA panel bg, #1E40AF accent) for visual consistency across
 * the listings-related pages, hardcoded rather than CSS custom properties
 * to match listing-detail.css's own approach.
 *
 * The filter pills (.sr-filter-pill/.sr-filter-pill-panel) are the same
 * native-<details>, position: absolute floating-panel pattern already built
 * for market-report-listings.php's Price/Beds & Baths/Sq Ft/More Filters
 * pills — reused here under this page's own "sr-" class prefix (that page
 * is a standalone HTML document with its own inline <style>, so the rules
 * can't be shared directly across files, only the pattern). Property
 * Type/Listing Type use the same <details> pill pattern too, just with a
 * vertical checkbox list (.sr-filter-pill-panel--checkboxes) in the panel
 * instead of side-by-side min/max fields.
 */

.sr-wrap {
  max-width: 1140px;
  margin: 0 auto;
  padding: 24px 16px 48px;
  color: #12233D;
}

/* ---- Search bar: the page's single most dominant element, but ---- */
/* proportionate — constrained to a max-width rather than spanning the
   full page width, with modest (not oversized) height/padding. */

/* Wraps .sr-searchbar (max-width: 640px, so it never spans this row's
   full width) — space-between is a no-op with this single flex child,
   kept in case another element joins this row later. */
.sr-search-top-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 20px;
}

.sr-searchbar {
  display: flex;
  gap: 10px;
  max-width: 640px;
  flex: 1 1 auto;
  margin-bottom: 0;
}

.sr-search-input {
  flex: 1 1 auto;
  font-size: 16px;
  padding: 12px 16px;
  border: 2px solid #DCE1E8;
  border-radius: 8px;
  color: #12233D;
}

.sr-search-input:focus {
  outline: none;
  border-color: #1E40AF;
}

.sr-search-btn {
  font-size: 14px;
  font-weight: 700;
  background: #1E40AF;
  color: #FFFFFF;
  border: none;
  padding: 0 22px;
  border-radius: 8px;
  cursor: pointer;
}

.sr-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 12px;
}

.sr-field label {
  color: #5B6B82;
  font-weight: 600;
}

.sr-field select,
.sr-field input {
  font-size: 13px;
  padding: 8px 10px;
  border: 1px solid #DCE1E8;
  border-radius: 6px;
  background: #FFFFFF;
  color: #12233D;
  min-width: 140px;
}

/* ---- Filter pills — same pattern as market-report-listings.php ---- */

/* position: relative + an explicit z-index (rather than the default
   "auto") makes this row a real stacking context of its own, not just a
   positioned element. This half of the Map view dropdown-clipping fix on
   its own turned out NOT to be sufficient — see .sr-map-container's own
   z-index: 0 below for the other, actually-necessary half and the full
   explanation of why. Short version: Leaflet's internal panes/controls
   carry real z-index values up to 1000, and without .sr-map-container
   establishing its own stacking context to contain them, those values
   compared directly against this row's z-index here at the page's root
   stacking context — where 1000 beats whatever this row's own z-index is
   set to. Both halves are needed together; this one lifts this row (and
   the pill panels inside it) out of the default z-index: auto
   paint-order-only bucket, the other keeps Leaflet's own values from
   leaking past its own box in the first place.

   z-index: 3, not 2 — a second, separate stacking-context collision, this
   time in Grid view (no Leaflet involved at all): .sr-save-btn (the
   heart/save icon overlaid on every card's photo) is also position:
   absolute with its own explicit z-index, which — since NEITHER of its
   own ancestors up to <body> sets an explicit z-index of their own (see
   that rule's comment) — makes it participate directly in this same
   page-root stacking context as this row, not some inner context this
   row's own z-index could ever contain or outrank internally regardless
   of how high it's set (.sr-filter-pill-panel's own z-index: 10 is
   scoped entirely inside THIS row's stacking context — see that rule's
   comment — so it was never the actual number in play here). At the
   root level the two used to collide exactly (.sr-save-btn's z-index: 2
   == this row's old z-index: 2), and CSS breaks an exact tie by paint/DOM
   order, not visual intent — .sr-grid (and every .sr-save-btn inside it)
   comes AFTER this row in the markup, so the tie went to the heart icons,
   confirmed live via getComputedStyle() on both elements' full ancestor
   chains rather than assumed from the numbers alone. Raised to 3 purely
   to clear that specific z-index: 2 outright instead of relying on DOM
   order to break a tie that happened to fall the right way. */
.sr-filters-row {
  position: relative;
  z-index: 3;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin-bottom: 24px;
  padding-bottom: 20px;
  border-bottom: 1px solid #EEF1F5;
}

.sr-filter-pills {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

.sr-filter-pill {
  position: relative;
}

.sr-filter-pill summary {
  display: inline-flex;
  align-items: center;
  list-style: none;
  cursor: pointer;
  user-select: none;
  font-size: 13px;
  font-weight: 600;
  line-height: 1;
  padding: 8px 16px;
  border: 1px solid #DCE1E8;
  border-radius: 999px;
  background: #FFFFFF;
  color: #12233D;
}

.sr-filter-pill summary::-webkit-details-marker {
  display: none;
}

.sr-filter-pill summary::marker {
  content: '';
}

.sr-filter-pill[open] summary {
  border-color: #1E40AF;
}

/* Price/Beds & Baths/Sq Ft (plain number inputs) and More Filters'
   selects (Pool/HOA/Distressed/Price Changed Recently) can tell "has a
   value" apart from "still blank/Any" directly from DOM state alone, so
   a :has() heuristic is enough for those. Property Type/Listing Type/
   Status can't: multi-select checkboxes have no reliable DOM-only way to
   tell "the visitor explicitly selected this" apart from "this is just
   how it renders by default" (Listing Type's own For Sale checkbox in
   particular renders pre-checked on a totally untouched page load, see
   parseSearchFilterState()'s own fallback) — those three get an
   explicit .sr-filter-pill--active class instead, computed server-side
   in views/search.php from the exact same condition each one's own
   removable active-filter chip already uses, so the pill and its chip
   can never visually disagree. */
.sr-filter-pill:has(input[type="number"]:not(:placeholder-shown)) summary,
.sr-filter-pill:has(select option:checked:not([value=""])) summary,
.sr-filter-pill--active summary {
  background: #1E40AF;
  border-color: #1E40AF;
  color: #FFFFFF;
}

.sr-filter-pill-panel {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  /* Only needs to beat this row's own siblings now that .sr-filters-row
     itself establishes the real stacking context above the map — see
     that rule's comment. Still comfortably higher than anything else in
     this row (e.g. .sr-active-pill-remove's z-index: 2). */
  z-index: 10;
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  background: #FFFFFF;
  border: 1px solid #DCE1E8;
  border-radius: 8px;
  padding: 14px;
  box-shadow: 0 8px 24px rgba(18, 35, 61, 0.16);
  width: max-content;
  max-width: 320px;
}

/* Property Type/Listing Type panels: a plain vertical list of checkboxes
   rather than the side-by-side min/max fields the base panel layout above
   is shaped for. */
.sr-filter-pill-panel--checkboxes {
  flex-direction: column;
  flex-wrap: nowrap;
  gap: 10px;
}

.sr-checkbox-row {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: #12233D;
  cursor: pointer;
  white-space: nowrap;
}

.sr-checkbox-row input {
  margin: 0;
}

.sr-filters-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin-left: auto;
}

.sr-filters-actions label {
  font-size: 13px;
  font-weight: 600;
  color: #5B6B82;
}

.sr-filters-actions select {
  font-size: 13px;
  font-weight: 600;
  padding: 8px 12px;
  border: 1px solid #DCE1E8;
  border-radius: 6px;
  background: #FFFFFF;
  color: #12233D;
  cursor: pointer;
  min-width: 90px;
}

.sr-filters-row button {
  font-size: 13px;
  font-weight: 600;
  background: #1E40AF;
  color: #FFFFFF;
  border: none;
  padding: 8px 16px;
  border-radius: 6px;
  cursor: pointer;
}

.sr-error,
.sr-empty {
  font-size: 14px;
  color: #5B6B82;
  padding: 40px 0;
  text-align: center;
}

/* ---- Active-filter pills + Draw Area/Grid/Map controls: one shared row ---- */
/* .sr-results-row holds both .sr-active-filters (below) and
   .sr-view-controls (further below — Draw Area + the Grid/Map toggle,
   grouped as one unit) as side-by-side flex items, rather than each
   stacked in its own full-width row — the toggle used to sit in its own
   row beneath the pills with a visible gap of empty space next to it
   whenever there were few enough pills not to need that full width.
   Only .sr-active-filters is allowed to wrap/shrink (flex: 1 1 auto +
   min-width: 0, plus its own internal flex-wrap below) — .sr-view-controls
   stays flex: 0 0 auto (its own fixed content width, never shrinks) with
   margin-left: auto, which pushes the WHOLE group to the row's right
   edge whether or not .sr-active-filters is even present (that element
   only renders at all when at least one filter is active — see
   views/search.php). Any number of pills is safe: because
   .sr-active-filters can shrink below its own content's full width, the
   browser wraps ITS pills onto as many internal lines as needed rather
   than ever forcing .sr-view-controls out of the row — confirmed live
   with 5 simultaneous filters at both a desktop and a ~768px tablet
   width, the group stayed put at top-right through 1, 2, and 3 wrapped
   pill lines. align-items: flex-start keeps the group pinned to the TOP
   of the row once pills wrap past one line, instead of drifting to
   vertically center against the pills' full wrapped height. Below 640px
   this reverts to the original stacked-and-centered arrangement instead
   (see that breakpoint below) — a pill's own text has no width floor of
   its own to shrink below without wrapping mid-pill (which would look
   broken, a pill chip isn't built to wrap), so at phone widths there
   isn't reliably enough spare room beside the group for even one pill
   without risking exactly that; stacking removes the risk entirely
   rather than trying to cut it close. */
.sr-results-row {
  display: flex;
  align-items: flex-start;
  flex-wrap: wrap;
  gap: 12px 16px;
  margin: 12px 0 20px;
}

/* ---- Active filter pills — one chip per filter explicitly present in
   the query string. Distinct from .sr-filter-pill above (that's the
   dropdown TRIGGER for editing a filter's value); these are a read-only
   summary of what's currently applied, each one a plain link back to the
   search with just that filter's own param(s) removed. */
.sr-active-filters {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.sr-active-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  border: 1px solid #DCE1E8;
  border-radius: 999px;
  background: #F7F8FA;
  color: #12233D;
  font-size: 13px;
  font-weight: 600;
  text-decoration: none;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.sr-active-pill:hover {
  background: #FFFFFF;
  border-color: #1E40AF;
  color: #1E40AF;
}

.sr-active-pill-remove {
  font-size: 15px;
  line-height: 1;
  color: #5B6B82;
}

.sr-active-pill:hover .sr-active-pill-remove {
  color: #1E40AF;
}

/* ---- Results grid ---- */

.sr-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 20px;
  margin-bottom: 24px;
}

/* .sr-card-container wraps the card's own <a> (.sr-card) plus the save
   button as siblings, rather than nesting the button inside the link —
   see listing-card.php. It's the grid's actual direct child now; .sr-card
   itself keeps every visual rule below unchanged. */
.sr-card-container {
  position: relative;
}

.sr-card {
  display: block;
  text-decoration: none;
  color: inherit;
  border: 1px solid #DCE1E8;
  border-radius: 10px;
  overflow: hidden;
  background: #FFFFFF;
  transition: box-shadow 0.15s ease, border-color 0.15s ease;
}

.sr-card:hover {
  border-color: #1E40AF;
  box-shadow: 0 4px 14px rgba(18, 35, 61, 0.1);
}

.sr-card-thumb {
  aspect-ratio: 4 / 3;
  background: #F7F8FA;
  overflow: hidden;
}

.sr-card-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.sr-card-thumb-placeholder {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.sr-card-thumb-placeholder svg {
  width: 40%;
  height: 40%;
  color: #C2CBD6;
}

.sr-card-body {
  padding: 14px 16px 16px;
}

.sr-card-price {
  font-size: 20px;
  font-weight: 800;
  margin: 0 0 4px;
}

.sr-card-address {
  font-size: 14px;
  margin: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.sr-card-city {
  font-size: 13px;
  color: #5B6B82;
  margin: 0 0 10px;
}

.sr-card-facts {
  display: flex;
  gap: 12px;
  font-size: 13px;
  color: #5B6B82;
  padding-top: 10px;
  border-top: 1px solid #EEF1F5;
}

/* ---- Save/heart button — overlaid on every card's thumbnail corner ---- */
/* Sibling of .sr-card (see .sr-card-container above), positioned via the
   container rather than relative to .sr-card-thumb specifically, since
   that's simpler than reaching into the <a>'s own box. js/saved-listings.js
   toggles .js-save-btn--saved based on localStorage state read on load. */

.sr-save-btn {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border: none;
  border-radius: 50%;
  background: rgba(18, 35, 61, 0.55);
  color: #FFFFFF;
  cursor: pointer;
  padding: 0;
  transition: background 0.15s ease, color 0.15s ease;
}

.sr-save-btn:hover {
  background: rgba(18, 35, 61, 0.75);
}

.sr-save-btn svg {
  width: 18px;
  height: 18px;
}

.sr-save-btn.js-save-btn--saved {
  color: #E0245E;
  background: #FFFFFF;
}

.sr-save-btn.js-save-btn--saved svg {
  fill: currentColor;
}

.sr-save-btn:focus-visible {
  outline: 2px solid #1E40AF;
  outline-offset: 2px;
}

/* ---- Status badge — overlaid on every card's thumbnail, opposite ---- */
/* corner from the save button. A sibling of .sr-card (see .sr-save-btn's
   own comment above for why: nesting inside .sr-card-thumb, which has
   overflow: hidden, would clip it unless it also escaped that overflow
   via a positioned-ancestor trick — simpler to just follow the same
   sibling pattern the save button already uses). Color/label driven by
   listing-card.php's own listingCardStatusBadge(). */
.sr-card-status {
  position: absolute;
  top: 10px;
  left: 10px;
  z-index: 2;
  padding: 3px 9px;
  border-radius: 4px;
  font-size: 12px;
  font-weight: 700;
  color: #FFFFFF;
  line-height: 1.4;
}

.sr-status-active {
  background: #1E9E5A;
}

.sr-status-under-contract {
  background: #C58C00;
}

.sr-status-sold {
  background: #C23A3A;
}

/* ---- views/saved.php's own heading ---- */

.saved-heading {
  font-size: 28px;
  margin: 0 0 8px;
  color: #12233D;
}

/* ---- views/saved.php's own "Not you? Change" link ---- */
/* Clears the remembered email (js/saved-listings.js's clearSavedEmail())
   and re-shows the email prompt — see that page's own script. */
.saved-not-you {
  font-size: 13px;
  color: #5B6B82;
  margin: 0 0 20px;
}

.saved-not-you a {
  color: #1E40AF;
  font-weight: 600;
  text-decoration: none;
}

.saved-not-you a:hover {
  text-decoration: underline;
}

/* ---- views/saved.php's own "email confirmed" banner ---- */
/* Shown once when this page is reached via confirm-saved-email.php's own
   ?confirmed=1 redirect — see that page's script. */
.saved-confirmed-banner {
  font-size: 14px;
  font-weight: 600;
  color: #14532D;
  background: #E7F6EC;
  border: 1px solid #BFE6CA;
  border-radius: 6px;
  padding: 10px 14px;
  margin: 0 0 16px;
}

/* ---- Email-capture prompt (save-button flow + views/saved.php) ---- */
/* One shared component (js/saved-listings.js's buildEmailPromptEl()),
   mounted two different ways: inline here (.save-email-prompt on its
   own, no modal wrapper — views/saved.php's own "no email remembered"
   empty state), or inside .save-email-modal below (every save-button
   click when no email is remembered yet). */
.save-email-prompt {
  max-width: 360px;
  margin: 0 auto;
  padding: 24px 0;
  text-align: center;
}

.save-email-prompt-text {
  font-size: 14px;
  color: #4B5A70;
  margin: 0 0 14px;
}

.save-email-prompt-form {
  display: flex;
  gap: 8px;
}

.save-email-prompt-input {
  flex: 1 1 auto;
  min-width: 0;
  padding: 10px 12px;
  border: 1px solid #DCE1E8;
  border-radius: 6px;
  font-size: 14px;
  font-family: inherit;
  color: #12233D;
}

.save-email-prompt-input:focus {
  outline: none;
  border-color: #1E40AF;
}

.save-email-prompt-submit {
  flex: 0 0 auto;
  padding: 10px 18px;
  border: none;
  border-radius: 6px;
  background: #1E40AF;
  color: #FFFFFF;
  font-size: 14px;
  font-weight: 700;
  font-family: inherit;
  cursor: pointer;
}

.save-email-prompt-submit:hover {
  background: #16327F;
}

.save-email-prompt-error {
  font-size: 13px;
  color: #B91C1C;
  margin: 8px 0 0;
}

/* ---- Modal wrapper around .save-email-prompt above ---- */
/* Used only by the save-button click flow (showEmailPromptModal()) — a
   fixed, centered overlay rather than a popover anchored to the button
   itself, since a save button can sit inside a narrow/overflow-hidden
   card (grid cards, the map view's compact sidebar rows) that would
   clip an inline popover. */
.save-email-modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  background: rgba(18, 35, 61, 0.55);
}

.save-email-modal {
  position: relative;
  width: 100%;
  max-width: 400px;
  background: #FFFFFF;
  border-radius: 10px;
  padding: 8px 20px 0;
  box-shadow: 0 12px 32px rgba(18, 35, 61, 0.3);
}

.save-email-modal .save-email-prompt {
  padding: 28px 0 24px;
}

.save-email-modal-close {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 28px;
  height: 28px;
  border: none;
  border-radius: 50%;
  background: none;
  color: #5B6B82;
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
}

.save-email-modal-close:hover {
  background: #F7F8FA;
  color: #12233D;
}

/* ---- Pagination — same pattern as market-report-listings.php ---- */

.sr-pagination {
  display: flex;
  align-items: center;
  gap: 14px;
  font-size: 13px;
}

.sr-pagination a {
  color: #1E40AF;
  text-decoration: none;
  font-weight: 600;
}

.sr-pagination .sr-pagination-disabled {
  color: #A6B0BF;
}

/* flex-wrap here is purely a safety net for the Map view's narrow list
   panel (see .sr-map-list below) — grid view's own wide pagination row
   never has cause to wrap, this changes nothing there. */
.sr-pagination {
  flex-wrap: wrap;
}

/* ---- Draw Area + Grid/Map view toggle group ---- */
/* Shares .sr-results-row with the active-filter pills now — flex: 0 0
   auto + margin-left: auto keeps this WHOLE group (not just the toggle
   alone) pinned to the row's right edge regardless of whether
   .sr-active-filters is even present, with Draw Area (map view only)
   and the toggle laid out left-to-right inside it via gap — so the
   toggle always ends up the rightmost element in the row, and Draw Area
   always sits immediately to its left, never separated by however much
   leftover space happens to be in the row. */
.sr-view-controls {
  flex: 0 0 auto;
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 12px;
}

.sr-view-toggle {
  display: flex;
  border: 1px solid #DCE1E8;
  border-radius: 8px;
  overflow: hidden;
}

.sr-view-toggle-link {
  padding: 10px 16px;
  font-size: 13px;
  font-weight: 700;
  color: #5B6B82;
  background: #FFFFFF;
  text-decoration: none;
  white-space: nowrap;
}

.sr-view-toggle-link + .sr-view-toggle-link {
  border-left: 1px solid #DCE1E8;
}

.sr-view-toggle-link:hover {
  background: #F7F8FA;
}

.sr-view-toggle-link--active,
.sr-view-toggle-link--active:hover {
  background: #1E40AF;
  color: #FFFFFF;
}

/* ---- Map view ---- */
/* List panel (fixed width, its own scroll) beside the map (fills the
   rest of the row) — side by side down to 900px, deliberately wider
   than this file's other (640px) breakpoint: a real list panel next to
   a usable map needs more room than a single reflowing grid does before
   the two-column layout stops working. */
.sr-map-view {
  display: flex;
  align-items: flex-start;
  gap: 20px;
  margin-bottom: 24px;
}

/* Width: percentage-based, not a flat px figure — ~20%/80% list/map
   split (pushed further toward the map than an earlier ~28%/72% pass —
   the list panel now holds the .sr-compact-* condensed row component
   below, not full grid cards, so it reads fine considerably narrower
   than it needed to when it had to fit a full card's width) holds steady
   as the container's own width changes, unlike a fixed px list which
   would eat a growing share of a narrower desktop viewport as
   .sr-map-container (flex: 1 1 auto below) gives up space to it
   disproportionately. min-width keeps the compact rows from getting too
   cramped to read as this approaches the 900px mobile breakpoint, where
   the layout switches to stacked (full-width list above/below a
   full-width map) instead.

   Height: viewport-relative, not a flat px figure either — a fixed
   height tall enough for a spacious viewport left this row taller than
   the page on shorter ones, forcing the whole page (not just this list)
   to scroll just to reach the bottom of the map. 260px is everything
   that can sit above this row (nav/header, search bar, the filter-pill
   row, and — when any filter is active — the active-filter-pill chips
   row); measured against a real render (with active pills showing)
   rather than guessed, with a little slack on top since the pills can
   still wrap to two lines on a narrower desktop width. Trimmed down from
   an earlier 340px specifically to make the map (and the compact list
   beside it) taller, not just narrower-relative-to-wider-map — a bigger
   map was asked for on both axes, not just width share. min-height keeps
   this from collapsing to something unusably short on a very short
   viewport — a bit of page scroll in that edge case is an acceptable
   trade for not shrinking the map into uselessness. */
.sr-map-list {
  flex: 0 0 20%;
  max-width: 20%;
  min-width: 260px;
  height: calc(100vh - 260px);
  min-height: 480px;
  overflow-y: auto;
  padding-right: 4px;
}

.sr-map-list-cards {
  display: flex;
  flex-direction: column;
  margin-bottom: 16px;
}

/* position: relative anchors .sr-map-cap-message (position: absolute)
   below — see that rule. z-index: 0 is doing real work here, not just
   decoration: position: relative alone does NOT establish a stacking
   context (only position + an actual z-index value does), so without
   this, Leaflet's own internal .leaflet-pane/.leaflet-marker-pane/
   .leaflet-top elements — which carry real, hardcoded z-index values up
   to 1000 in Leaflet's own stylesheet — aren't contained by this
   container at all. They'd escape straight up to whatever the nearest
   ACTUAL stacking-context ancestor is (the page root, absent this), and
   get compared directly against .sr-filters-row's own z-index there —
   1000 beats whatever that's set to, so the map's own controls/markers
   would paint above the filter-pill dropdowns regardless of that row's
   own z-index. Confirmed
   live: .sr-filters-row's z-index fix alone did not fix the Map view
   dropdown-clipping bug (elementFromPoint reported the dropdown's own
   content as topmost, yet the map still visually painted over it) —
   this is why. With this container now establishing its own stacking
   context, every Leaflet z-index up to 1000 is only ever compared
   against other Leaflet panes/controls inside this same box, never
   against page UI outside it. */
.sr-map-container {
  position: relative;
  z-index: 0;
  flex: 1 1 auto;
  min-width: 0;
  /* Same 260px figure as .sr-map-list's own height above — the two sit
     side by side and must always match, see that rule's comment for
     what the figure represents and why it was trimmed down from 340px. */
  height: calc(100vh - 260px);
  min-height: 480px;
}

.sr-map {
  width: 100%;
  height: 100%;
  border-radius: 10px;
  overflow: hidden;
  border: 1px solid #DCE1E8;
}

/* Hover-sync: a marker hovered on the map highlights its matching list
   row (js/search-map.js toggles this class) — a background tint rather
   than grid view's border/shadow treatment (.sr-compact-card has no
   border of its own to change, just the border-bottom divider between
   rows — see that rule below), no layout shift either way. */
.sr-map-list-card--active .sr-compact-card {
  background: #EEF3FC;
}

/* ---- Map view: compact sidebar list rows ---- */
/* A distinct component from .sr-card/.sr-card-container above (grid
   view's own, larger card) — purpose-built for .sr-map-list's narrow
   column so several listings are visibly stacked and scrollable there at
   once, rather than one oversized card filling the whole panel. Rendered
   by both listing-card.php's renderCompactListingCard() (the initial
   server-side paint) and js/search-map.js's compactCardHtml() (every
   re-render after a pan/zoom) — same markup/classes either way. */

.sr-compact-card-container {
  position: relative;
}

.sr-compact-card {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 30px 8px 4px;
  text-decoration: none;
  color: inherit;
  border-bottom: 1px solid #EEF1F5;
  border-radius: 6px;
  transition: background 0.15s ease;
}

.sr-compact-card:hover {
  background: #F7F8FA;
}

.sr-compact-card-thumb {
  flex: 0 0 auto;
  width: 84px;
  height: 84px;
  border-radius: 6px;
  overflow: hidden;
  background: #F7F8FA;
}

.sr-compact-card-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.sr-compact-card-thumb-placeholder {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.sr-compact-card-thumb-placeholder svg {
  width: 45%;
  height: 45%;
  color: #C2CBD6;
}

/* min-width: 0 — same overflow-fix category as this file's own
   .sr-map-container/.hp-community-card elsewhere: a flex item's default
   min-width: auto would otherwise refuse to shrink below the (unwrapped,
   ellipsis-truncated) address/facts text's own natural width, which is
   comfortably wider than this narrow column has room for. */
.sr-compact-card-body {
  flex: 1 1 auto;
  min-width: 0;
}

.sr-compact-card-price {
  font-size: 15px;
  font-weight: 800;
  color: #12233D;
  margin: 0;
}

.sr-compact-card-address {
  font-size: 13px;
  color: #12233D;
  margin: 2px 0 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.sr-compact-card-facts {
  font-size: 12px;
  color: #5B6B82;
  margin: 2px 0 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Smaller counterpart to .sr-save-btn above, sized for this row's own
   60px thumbnail instead of the grid card's much larger one — same
   states/behavior (js/saved-listings.js toggles js-save-btn--saved on
   this exactly like it does on .sr-save-btn, that class is what it
   actually looks for, not the size-specific one). */
.sr-compact-save-btn {
  position: absolute;
  top: 8px;
  right: 2px;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border: none;
  border-radius: 50%;
  background: rgba(18, 35, 61, 0.55);
  color: #FFFFFF;
  cursor: pointer;
  padding: 0;
  transition: background 0.15s ease, color 0.15s ease;
}

.sr-compact-save-btn:hover {
  background: rgba(18, 35, 61, 0.75);
}

.sr-compact-save-btn svg {
  width: 13px;
  height: 13px;
}

.sr-compact-save-btn.js-save-btn--saved {
  color: #E0245E;
  background: #FFFFFF;
}

.sr-compact-save-btn.js-save-btn--saved svg {
  fill: currentColor;
}

.sr-compact-save-btn:focus-visible {
  outline: 2px solid #1E40AF;
  outline-offset: 2px;
}

/* Smaller counterpart to .sr-card-status above, positioned to land on
   this row's own smaller thumbnail — see .sr-compact-card's own
   padding (8px 30px 8px 4px): the thumb sits 4px from the container's
   left edge and 8px from its top, which these offsets match. */
.sr-compact-card-status {
  position: absolute;
  top: 8px;
  left: 4px;
  z-index: 2;
  padding: 2px 6px;
  border-radius: 3px;
  font-size: 10px;
  font-weight: 700;
  color: #FFFFFF;
  line-height: 1.4;
}

/* Custom price-chip marker (js/search-map.js's L.divIcon) — a rounded
   rectangle, not a full pill, matching the reference marker style.
   iconSize: null on the divIcon means Leaflet doesn't force a fixed box
   around this, so it sizes to the price label's own natural width
   ("519K" vs "1.2M" aren't the same length) rather than clipping or
   leaving odd padding. */
.sr-map-marker-icon {
  background: transparent;
  border: none;
}

.sr-map-marker-pill {
  display: inline-block;
  padding: 6px 10px;
  background: #1E40AF;
  color: #FFFFFF;
  font-size: 12px;
  font-weight: 700;
  border-radius: 6px;
  border: 2px solid #FFFFFF;
  box-shadow: 0 2px 6px rgba(18, 35, 61, 0.35);
  white-space: nowrap;
  cursor: pointer;
  transition: background 0.15s ease, transform 0.15s ease;
}

/* Hover-sync the other direction: a list card hovered highlights its
   matching marker (same js/search-map.js). Also applies on the marker's
   own direct :hover, so mousing over it on the map gets the same
   emphasis without waiting on the mouseover handler round-trip. */
.sr-map-marker-icon--active .sr-map-marker-pill,
.sr-map-marker-pill:hover {
  background: #12233D;
  transform: scale(1.12);
}

/* Below js/search-map.js's own ZOOM_STYLE_THRESHOLD, markers render as
   this small dot instead of .sr-map-marker-pill above — see that
   constant's own comment for why (a wide/metro view with hundreds of
   price-label rectangles visually merges into a solid mass; plain dots
   stay legible as individual points at that same density). Sized in
   both this rule and dotIcon()'s own iconSize/iconAnchor together —
   changing one without the other would make the visible dot drift off
   its actual lat/lng anchor point. */
.sr-map-marker-dot {
  display: block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: #1E40AF;
  border: 2px solid #FFFFFF;
  box-shadow: 0 1px 4px rgba(18, 35, 61, 0.45);
  cursor: pointer;
  transition: background 0.15s ease, transform 0.15s ease;
}

.sr-map-marker-icon--active .sr-map-marker-dot,
.sr-map-marker-dot:hover {
  background: #12233D;
  transform: scale(1.5);
}

/* Leaflet's own tooltip, shown on hover for dot markers only (see
   marker.bindTooltip() in js/search-map.js's renderMarkers()) — restyled
   to match .sr-map-marker-pill's own look rather than Leaflet's plain
   white-box default, so a dot's price reads as the same kind of chip a
   rectangle marker would show permanently, just appearing on hover
   instead of always-on. */
.leaflet-tooltip {
  padding: 4px 8px;
  background: #12233D;
  color: #FFFFFF;
  font-size: 11px;
  font-weight: 700;
  border: none;
  border-radius: 5px;
  box-shadow: 0 2px 6px rgba(18, 35, 61, 0.35);
}

.leaflet-tooltip-top:before {
  border-top-color: #12233D;
}

/* Shown by js/search-map.js only when a bounded fetch hits
   search-map-data.php's own marker cap ("Showing 500 of 1,400 homes in
   this area — zoom in to see more") — hidden (via the [hidden]
   attribute in the markup) the rest of the time, so this rule only ever
   needs to worry about the visible case. Floated over the map's own
   top-RIGHT corner rather than pushing the map container's layout
   around — Leaflet's own default zoom control sits top-left (see
   .leaflet-control-zoom-in/-out), so top-left here would sit directly
   on top of it and block those buttons entirely; top-right has nothing
   else there to collide with. */
.sr-map-cap-message {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 1000;
  margin: 0;
  padding: 6px 12px;
  background: rgba(18, 35, 61, 0.85);
  color: #FFFFFF;
  font-size: 12px;
  font-weight: 600;
  border-radius: 6px;
  max-width: calc(100% - 20px);
  box-sizing: border-box;
}

/* Lives in .sr-view-controls next to .sr-view-toggle now (views/search.php,
   map view only) rather than floating on top of the map itself — map
   controls belong in the surrounding UI, not overlaid on the map
   surface. No position/z-index needed anymore now that it's a normal
   inline element in that row, not competing with Leaflet's own
   internal panes for stacking order. Same filled-accent button styling
   as .sr-search-btn — this site's one established "primary action
   button" look — rather than Leaflet.draw's own default toolbar UI
   (deliberately never loaded as a visible control, see layouts/head.php's
   own comment on why the plugin's CSS is present but unused for that).
   One element whose label/class js/search-map.js toggles between
   "Draw Area" and "Clear Shape" — see that file — not two
   separately-styled buttons. */
.sr-draw-area-btn {
  flex: 0 0 auto;
  font-size: 13px;
  font-weight: 700;
  background: #1E40AF;
  color: #FFFFFF;
  border: none;
  padding: 10px 16px;
  border-radius: 8px;
  cursor: pointer;
}

.sr-draw-area-btn:hover {
  background: #16327F;
}

/* "Clear Shape" state (js/search-map.js toggles this class once a shape
   is completed) — an outline treatment rather than the same solid fill,
   so it reads as a distinct (reset/undo-flavored) action from "Draw
   Area" itself despite being the exact same element. */
.sr-draw-area-btn--active {
  background: #FFFFFF;
  color: #1E40AF;
  border: 1.5px solid #1E40AF;
}

.sr-draw-area-btn--active:hover {
  background: #F7F8FA;
}

@media (max-width: 900px) {
  .sr-map-view {
    flex-direction: column;
  }

  .sr-map-list {
    flex: 0 0 auto;
    width: 100%;
    max-width: 100%;
    height: auto;
    max-height: 420px;
  }

  .sr-map-container {
    width: 100%;
    height: 420px;
  }
}

@media (max-width: 640px) {
  .sr-search-top-row {
    flex-direction: column;
    align-items: stretch;
  }

  .sr-searchbar {
    flex-direction: column;
  }

  .sr-search-btn {
    padding: 12px;
  }

  /* .sr-searchbar's own flex-direction: column above (this same media
     query) would otherwise stretch this icon button's width to the row's
     full width, same as every other stacked child here — it's the one
     child that should stay its own small square regardless. */
  .sr-save-search-btn {
    align-self: center;
  }

  /* Reverts to the original stacked arrangement below this width — see
     .sr-results-row's own comment (above, near .sr-active-filters) for
     why phone widths specifically don't get the inline desktop/tablet
     layout. */
  .sr-results-row {
    flex-direction: column;
    align-items: stretch;
  }

  .sr-view-controls {
    margin-left: 0;
    align-self: center;
  }

  /* ---- Filter trigger pills (Property Type/Listing Type/Price/etc.) ---- */
  /* Below this width, .sr-filters-row stacks its two children — the pill
     strip, then Sort/Apply — full-width instead of the desktop/tablet
     flex-wrap row (6 pill buttons wrapping across 2-3 uneven lines was
     the actual "ugly" complaint this was written for).

     flex-wrap: nowrap here too, not just on .sr-filter-pills below — the
     base (desktop) rule's own flex-wrap: wrap, left active on THIS
     element, doesn't just fail to matter once there's only two children
     stacked in a column; confirmed live it actively breaks their width.
     align-items: stretch sizes each child to this row's own cross-axis
     (horizontal) width, but flex-wrap: wrap apparently still lets the
     browser compute that stretch basis against .sr-filter-pills' own
     unwrapped min-content width (its 6 non-shrinking pills, easily
     400px+) rather than this row's actual 300-and-some px width —
     .sr-filter-pills and .sr-filters-actions both measured wider than
     their own parent as a result, well past .sr-wrap's edge. Forcing
     nowrap here (this row only ever has these two children now, never
     more than fit in one column) was the one change that actually fixed
     it, isolated by testing each property individually rather than
     guessed. */
  .sr-filters-row {
    flex-direction: column;
    flex-wrap: nowrap;
    align-items: stretch;
  }

  /* One horizontally-scrolling line instead of wrapping — flex-wrap:
     nowrap + overflow-x: auto. views/search.php's own toggle-listener
     script (see that file) handles the one real side effect of this:
     the CSS Overflow spec computes overflow-y to 'auto' too whenever
     overflow-x isn't 'visible' (confirmed live before writing this —
     without that script's fix, .sr-filter-pill-panel's default
     position: absolute gets silently clipped by that forced overflow-y
     the instant a filter panel would render taller than this one-line
     strip, not just scrolled out of reach but genuinely invisible, no
     matter how high its own z-index is set — the same "trapped by an
     ancestor, z-index number alone can't escape it" category of bug as
     .sr-filter-pill-panel's own z-index comment above already covers for
     stacking contexts, just the overflow-clipping variant of it here).
     .sr-filter-pill-panel's own position: fixed override below is the
     other half of that fix — escapes this clipping entirely, since a
     fixed-position element isn't clipped by an ancestor's overflow
     unless that ancestor sets transform/perspective/filter (none here
     do) the way it would be by position: absolute. */
  .sr-filter-pills {
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    padding-bottom: 6px;
  }

  .sr-filter-pill {
    flex: 0 0 auto;
  }

  /* Escapes .sr-filter-pills' clipping (see that rule's own comment) —
     top/left get set inline, in px, by views/search.php's own toggle
     script whenever a pill opens at this width, since position: fixed
     (unlike absolute) resolves top/left against the viewport, not
     against .sr-filter-pill, so a static CSS value could never actually
     track the correct pill. */
  .sr-filter-pill-panel {
    position: fixed;
  }

  /* Sort + Apply, centered as one group instead of hugging the left
     edge — margin-left: 0 first cancels the desktop-only margin-left:
     auto (see base rule) that used to push this against .sr-filter-pills
     in the old single shared row; centering it needs that gone first,
     otherwise the auto margin would fight justify-content for the same
     leftover space. */
  .sr-filters-actions {
    margin-left: 0;
    justify-content: center;
  }
}

/* ---- views/search.php's own "Save This Search" button ---- */
/* Icon-only floppy-disk button, living inside .sr-searchbar itself
   (a flex row, align-items defaults to stretch there) as the third
   child right after .sr-search-btn — so it naturally matches
   .sr-search-input/.sr-search-btn's own height with no rule of its own
   needed for that, and reads as "right next to Search" rather than the
   old labeled text button pushed off to the row's far right. Only
   rendered by views/search.php at all once at least one real filter is
   active (see that file's own $activeFilterPills-based check), so
   there's no "disabled/empty" state to style here — it's simply absent
   otherwise. */
.sr-save-search-btn {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  background: #1E40AF;
  color: #FFFFFF;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  padding: 0;
}

.sr-save-search-btn svg {
  width: 20px;
  height: 20px;
}

.sr-save-search-btn:hover {
  background: #16327F;
}

/* ---- views/saved.php's own "Saved Listings" / "Saved Searches" tabs ---- */
.saved-tabs {
  display: flex;
  gap: 4px;
  border-bottom: 1px solid #DCE1E8;
  margin: 0 0 20px;
}

.saved-tab {
  font-size: 14px;
  font-weight: 600;
  font-family: inherit;
  color: #5B6B82;
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  padding: 10px 14px;
  margin-bottom: -1px;
  cursor: pointer;
}

.saved-tab:hover {
  color: #12233D;
}

.saved-tab--active,
.saved-tab--active:hover {
  color: #1E40AF;
  border-bottom-color: #1E40AF;
}

/* ---- views/saved.php's own "Saved Searches" tab list ---- */
/* Rendered by js/saved-searches.js's renderSavedSearchesList() —
   .saved-search-row uses the same "flexible main content + fixed-width
   actions column" shape as .sr-active-pill's own row-level counterparts
   elsewhere in this file, just card-style rather than a chip. */
.saved-search-list {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.saved-search-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: flex-start;
  gap: 12px;
  padding: 16px;
  border: 1px solid #DCE1E8;
  border-radius: 8px;
  background: #FFFFFF;
}

.saved-search-main {
  flex: 1 1 260px;
  min-width: 0;
}

.saved-search-name {
  font-size: 16px;
  font-weight: 700;
  color: #12233D;
  margin: 0 0 4px;
}

.saved-search-summary {
  font-size: 13px;
  color: #4B5A70;
  margin: 0 0 6px;
}

.saved-search-meta {
  font-size: 12px;
  color: #8592A6;
  margin: 0 0 8px;
}

.saved-search-run-link {
  display: inline-block;
  font-size: 13px;
  font-weight: 600;
  color: #1E40AF;
  text-decoration: none;
}

.saved-search-run-link:hover {
  text-decoration: underline;
}

.saved-search-actions {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 10px;
}

.saved-search-toggle {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: #4B5A70;
  cursor: pointer;
  white-space: nowrap;
}

.saved-search-toggle input {
  margin: 0;
}

.saved-search-delete {
  font-size: 13px;
  font-weight: 600;
  color: #B91C1C;
  background: none;
  border: 1px solid #DCE1E8;
  border-radius: 6px;
  padding: 6px 12px;
  cursor: pointer;
}

.saved-search-delete:hover {
  background: #FDECEC;
  border-color: #F3B7B7;
}

.saved-search-delete:disabled {
  opacity: 0.6;
  cursor: default;
}
