/* ShowcaseIDX listings in the v2 layout (spec 2026-09-25). EVERY rule is
   under body.rt-sx, which the server sets only when our parts rendered and
   rt-sx.js toggles on SPA nav, so the /homes/ search view and outage renders
   are untouched. Layout is a grid on the EXISTING .rt-citypage__prose so no
   node inside or around ShowcaseIDX's React root is moved. */

/* max-width/margin only: NO horizontal padding on .rt-citypage__prose itself
   (code review 2026-09-25). .rt-citypage__body (rt-header.css) already
   supplies a 24px ambient gutter at every width -- the exact rule the
   first-party template's own .rt-mls-wrap relies on too (it declares none of
   its own either) -- so an additional padding here just stacked a SECOND
   24px on top of it: measured live, 48px total from 1024px up, where
   ShowcaseIDX never strips anything (see the mobile-gutter block below for
   the width range where it does).

   1320px, MATCHING v2, NOT v1's 1200 (code review 2026-09-26). v2 caps its
   own page at 1320px (`.rt-mls--v2 .rt-mls-wrap` / `.rt-mls-body >
   .rt-citypage__prose`, rt-mls-listing-v2.css), and this file's own
   grid-template-columns below already use v2's exact rail widths (380px from
   1024px, 452px from 1280px) with the same 28px gap -- only this max-width
   had been left at v1's number. At 1200px every SX listing above ~1248px was
   narrower than first-party, and RT_MLS_GALLERY_SIZES_V2's 840px `sizes`
   bucket (inc/mls/lib-redesign.php) described a slot this page never
   actually rendered (1200 - 452 - 28 = 720). At 1320 the arithmetic is
   1320 - 452 - 28 = 840, matching the constant exactly (see rt_sx_gallery_html()'s
   docblock in inc/sx-parts-lib.php). */
body.rt-sx .rt-citypage__prose { max-width: 1320px; margin: 0 auto; }
/* min-height is intentionally left alone here (code review 2026-09-25): the
   listing-detail polish printer (functions.php) sets `min-height: 100vh` on
   this same element as a load-flash / CLS guard (SIDX server-renders this
   container at ~zero height, so anything appended after it would jump into
   place once React mounts). That rule has no !important, so a `min-height: 0
   !important` here defeated it silently on every rt-sx render. Do not add it
   back without re-measuring layout-shift sources on a direct listing load. */
body.rt-sx .rt-citypage__prose > .sidx-container { max-width: none !important; padding-top: 0 !important; }

/* The duplicates our parts replace. .property-address-banner-placeholder is
   included because address-bar.js still wires the (now display:none, see
   the banner block in functions.php) banner on desktop, and once the visitor
   scrolls past its zero-height natural position it flips the placeholder to
   .is-active, a real 34px flow element (address-bar.css) -- measured live,
   that wiring runs even against a hidden banner (code review 2026-09-25).

   :is(body.rt-sx, body.rt-sx-wait) (code review 2026-09-25, CLS fix): the
   SAME hides also apply under body.rt-sx-wait, a class the gallery-order
   observer (functions.php) sets the moment it knows a v2-match hero is
   coming for the current listing (window.rtSxSync loaded) but before the
   fetch that carries .rt-sx-top/.rt-sx-rail has resolved. Without this, the
   vendor header/carousel/price/actions stayed fully visible and painted for
   the whole 0.5-1.2s round trip, then vanished in the same tick the hero was
   inserted above them: one large layout-shift entry, well outside the
   click's hadRecentInput window. Hiding them as soon as rt-sx-wait is set
   moves most of that same hide inside the window the click opened.

   THIS IS A PARTIAL FIX, MEASURED HONESTLY, NOT A COMPLETE ONE. Hiding early
   barely moves the COUNTED score by itself (fixture-measured: 0.4654 ->
   ~0.45), because nothing holds the vendor content's old space open -- the
   LATER swap-in still has to add the hero's full height back on its own. A
   reserved placeholder swapped in for the real content was tried in the
   same fixture and made the counted score WORSE (0.51), because sizing it
   without the SAME max-width/grid constraints that only apply once body.rt-sx
   (not body.rt-sx-wait) is set over-reserves at desktop widths -- not
   shipped for that reason. See functions.php's syncSxWait() and Task 6 Step
   6 of docs/superpowers/plans/2026-09-25-sidx-listing-v2-match.md for the
   live measurement this session added, which is what actually decides
   whether a properly-scoped reservation is worth building. */
:is(body.rt-sx, body.rt-sx-wait) .property-address-banner,
:is(body.rt-sx, body.rt-sx-wait) .property-address-banner-placeholder,
:is(body.rt-sx, body.rt-sx-wait) .sidx-main-header,
:is(body.rt-sx, body.rt-sx-wait) .sidx-menu,
:is(body.rt-sx, body.rt-sx-wait) .sidx-carousel,
:is(body.rt-sx, body.rt-sx-wait) .sidx-photo-array,
:is(body.rt-sx, body.rt-sx-wait) .sidx-price,
:is(body.rt-sx, body.rt-sx-wait) .sidx-sub-address,
:is(body.rt-sx, body.rt-sx-wait) .sidx-primary-action,
:is(body.rt-sx, body.rt-sx-wait) .sidx-actions,
:is(body.rt-sx, body.rt-sx-wait) .sidx-call-to-actions,
:is(body.rt-sx, body.rt-sx-wait) .rt-noacct,
:is(body.rt-sx, body.rt-sx-wait) .sidx-prev-nav-container #rt-viewall,
/* .sidx-price-area is the LEFT-COLUMN box holding both .sidx-price (already
   hidden above) and .sidx-days-online, a navy "N Days On Site" chip. Hiding
   only .sidx-price left that chip as an orphan, the first element of the
   main column, directly under the tabs (code review 2026-09-26). First-party
   shows the same fact inside the fact card's price line instead
   (rt-mls-listing-v2.php's .rt-mls-days); hiding the whole box here is the
   in-scope fix (adding that div would need the caller in functions.php,
   which builds $d, to pass a first-seen date -- out of this lane). */
:is(body.rt-sx, body.rt-sx-wait) .sidx-price-area,
/* Three legacy vendor/spot blocks that used to open the main column under
   the tabs, none of which exist on first-party (code review 2026-09-26):
   the elevated stats card (repeats Beds/Baths/Sq Ft/Built the fact card
   already shows), the centred "{street}, {city}" H2 (repeats the fact
   card's own aria-hidden headline), and the "Call Clark Smith..." box
   (repeats the fact card's + rail's own call line). Hidden rather than
   restyled: their content is a duplicate, not a distinct section, so there
   is nothing here worth keeping visible. */
:is(body.rt-sx, body.rt-sx-wait) .sidx-primary-info,
:is(body.rt-sx, body.rt-sx-wait) .property-address-h2,
:is(body.rt-sx, body.rt-sx-wait) .property-contact-text-below-description,
body.rt-sx .rt-citypage__prose > .rt-listing-crumbs:not(.rt-sx-crumbs) { display: none !important; }

/*
 * MOBILE GUTTER PARITY (code review 2026-09-25). Below 1024px ShowcaseIDX's
 * own small-screen mode strips the horizontal padding from EVERY non-sidx
 * ancestor of .sidx-container with an inline !important override -- the
 * documented full-bleed behaviour; page 9863 is deliberately excluded from
 * the theme's fix that reverts it (realhomes_child_sidx_fullbleed_fix() in
 * functions.php), because on the vendor-served /homes/ search view that
 * full-bleed IS the intended layout. .rt-citypage__body and
 * .rt-citypage__prose are both such ancestors, so whatever gutter they
 * supply disappears the instant ShowcaseIDX hydrates: measured live at
 * 390px (both an iPhone-13 emulation and a plain 390 viewport),
 * .rt-mls-facts, .rt-mls-h1 (inside it), .rt-mls-ctas (inside it) and
 * .rt-sx-crumbs all sat flush at the viewport edges post-hydration -- and,
 * before hydration, at x=48 (a doubled 24px+24px gutter, from
 * .rt-citypage__body's ambient plus .rt-citypage__prose's own padding,
 * which is why that padding was removed from the base rule above rather
 * than kept as a fallback). Either way a real, visible shift on hydration.
 *
 * A rule that only ADDS its own 24px on top of whatever ambient happens to
 * be present would still jump on hydration -- just 48px pre / 24px post
 * instead of 24 pre / 0 post. The fix instead makes each of these three
 * elements independent of the ambient ENTIRELY, using the SAME
 * viewport-relative bleed rt-mls-listing.css's `.rt-mls-gallery__stage`
 * already relies on: `width:100vw` plus `margin-left:calc(50% - 50vw)`
 * makes the box span exactly 0 to 100vw regardless of what padding its
 * ancestors currently carry (the calc resolves against whatever the
 * element's containing block happens to measure at that moment, so it is
 * correct whether the ambient is present, stripped, or anything in
 * between), and the element's OWN `padding-left/padding-right: 24px` then
 * re-adds a FIXED 24px inset on top of that (padding-top/bottom are left
 * exactly as each element's own base rule already sets them) --
 * `box-sizing:border-box` keeps the padding
 * inside the explicit 100vw instead of pushing the box past it.
 * `margin-right` is deliberately left undeclared: once `width` and
 * `margin-left` are both explicit, CSS's own over-constrained-box rule
 * (2.1 10.3.3) recalculates it to make the box fit, which is also why the
 * gallery's own rule never sets it either.
 *
 * The extra bleed step (beyond a plain padding declaration, which is all
 * .rt-listing-gallery / .rt-mls-map / .rt-listing-area need for the same
 * underlying reason) is needed here because those three sit as TOP-LEVEL
 * siblings of .sidx-container with nothing else between them and
 * .rt-citypage__prose, while .rt-mls-facts and .rt-sx-crumbs sit inside
 * .rt-mls-hero (a real box, not display:contents) -- a plain padding
 * declaration on them would ADD to whatever inset .rt-mls-hero's own
 * containing chain is currently supplying, not replace it.
 *
 * The gallery photo itself is deliberately left untouched: spec 4.2 has it
 * edge to edge below 761px on purpose (today's Redfin-style mobile hero),
 * and its existing bleed rule already resolves to that edge-to-edge result
 * regardless of ambient state, so there was nothing to fix there.
 *
 * Scoped to max-width:1023px because from 1024px .rt-mls-facts becomes its
 * own card with 26px/28px padding (rt-mls-listing-v2.css) and the tab row's
 * own @media(min-width:1024px) override (`margin:0;padding:0`) takes over --
 * neither of these rules is needed or wanted there, and ShowcaseIDX never
 * strips anything at that width in the first place.
 */
@media (max-width: 1023px) {
	body.rt-sx .rt-mls-facts,
	body.rt-sx .rt-mls-hero > .rt-sx-crumbs,
	body.rt-sx .rt-mls-tabs__row {
		width: 100vw; max-width: 100vw; margin-left: calc(50% - 50vw);
		padding-left: 24px; padding-right: 24px; box-sizing: border-box;
	}
	/* MAIN-COLUMN LEFT EDGES, mobile half (code review 2026-09-26). Below
	   1024px ShowcaseIDX's own small-screen mode strips .sidx-main-app-body's
	   padding to 0 (the same full-bleed behaviour the big comment above this
	   block describes for our own injected elements), so re-add the same
	   24px inset the facts/crumbs/tabs above already carry, with !important
	   to beat the vendor's own inline override the same way the rest of this
	   file counters vendor !important rules. */
	body.rt-sx .sidx-main-app-body { padding-left: 24px !important; padding-right: 24px !important; }
}

/* ShowcaseIDX's address <h1> stays the document's one h1, visible to
   crawlers and screen readers, not on screen. Never display:none.

   SCOPE FIX (code review 2026-09-25). The old `body.rt-sx .sidx-listing-heading`
   selector is (0,2,1), which LOSES `width` and `margin-left` to the polish
   printer's `body.rt-listing-detail .sidx-container .sidx-listing-heading`
   (functions.php) at (0,3,1) -- both !important, so specificity (not source
   order) decides, and the printer's is higher. Measured live: the element
   kept `position:absolute` and `height:1px` from here (nothing else set
   those), but `width` resolved to the printer's `100%` and `margin-left` to
   its `0`. With no positioned ancestor its containing block is the ICB
   (viewport), so `width:100%` is 100% of the VIEWPORT, not of any local
   column -- computed 1440px wide at a 1440px viewport, 390px at 390 -- and
   with the element's static (in-flow) position offset from the viewport's
   left edge by the page's own gutter, that full-viewport-width box pushed
   past the right edge: documentElement.scrollWidth measured 1575 at 1440
   (innerWidth 1440) and 429 at 390 (innerWidth 390), and scrollTo(300,0) /
   scrollTo(x,0) actually scrolled. `.sidx-container`'s `max-width:none` (this
   same file) does not clip it either -- clip only crops a box's own
   overflowing DESCENDANTS, and this box is itself the one overflowing its
   ancestors. Fixed by adding `.sidx-container` to the selector for a fourth
   class -- `body.rt-listing-detail.rt-sx .sidx-container .sidx-listing-heading`
   is (0,4,1), which beats the printer's (0,3,1) outright regardless of
   source order, so this rule's `width:1px` and `margin:-1px` (both
   !important) win instead. Re-verified: documentElement.scrollWidth equals
   innerWidth at both 1440 and 390, and the h1 is still present and reachable
   in the accessibility tree (position:absolute + clip does not remove it). */
body.rt-listing-detail.rt-sx .sidx-container .sidx-listing-heading {
	position: absolute !important; width: 1px !important; height: 1px !important; padding: 0 !important;
	margin: -1px !important; overflow: hidden !important; clip: rect(0 0 0 0) !important; white-space: nowrap !important; border: 0 !important;
}

/*
 * STICKY TAB BAR FIX (code review 2026-09-25, verified in Chromium AND WebKit
 * with a static HTML/CSS fixture; both engines agree byte-for-byte).
 *
 * .rt-mls-tabs reuses rt-mls-listing-v2.css's unconditional
 * `.rt-mls--v2 .rt-mls-tabs { position: sticky; top: var(--rt-v2-hdr) }`
 * (it applies at every width, not just desktop). A position:sticky element's
 * containing block is its parent box. rt_sx_top_html() (inc/sx-parts-lib.php)
 * puts .rt-mls-tabs inside .rt-mls-lower, and on this page .rt-mls-lower
 * wraps ONLY the <nav> -- unlike the v2 first-party template, where
 * .rt-mls-lower also wraps .rt-mls-cols (main content + rail), which is what
 * gives the nav's containing block enough height to actually pin. Left as a
 * plain nested box here, .rt-mls-lower's height equals the nav's own height,
 * so there is ~0px of room to stick in: verified in headless Chromium, the
 * nav's computed top went 200 (in flow) -> -480 -> -1280 -> -2146 across a
 * scroll instead of settling at the header offset.
 *
 * FIX: make .rt-sx-top and .rt-mls-lower transparent to layout everywhere
 * (not just >=1024px -- the sticky rule is unconditional, so mobile needs
 * this too), so .rt-mls-hero and .rt-mls-tabs become direct children of
 * .rt-citypage__prose, whose box spans the whole listing body. `display:
 * contents` removes only the BOX; the DOM node (and its
 * data-rt-listing-key attribute, which ensureProse/apply read) stays fully
 * queryable. Their own margin-top becomes a no-op once they generate no
 * box, so it has to move onto .rt-mls-hero -- but only inside the
 * `@media (min-width: 1024px)` block below, see the HEADER-GAP COLLAPSE
 * comment there for why an unconditional version of that rule broke
 * everything under 1024px.
 */
body.rt-sx .rt-sx-top, body.rt-sx .rt-sx-top > .rt-mls-lower { display: contents; }
/*
 * TABS GAP FIX (code review 2026-09-26). `display: contents` on
 * .rt-sx-top > .rt-mls-lower (above) makes v2's own
 * `.rt-mls--v2 .rt-mls-lower { margin-top: 20px }` (rt-mls-listing-v2.css) a
 * no-op here for the SAME reason the hero's margin-top had to move onto
 * .rt-mls-hero itself (see the HEADER-GAP COLLAPSE comment below): a
 * display:contents parent generates no box, so nothing is left to carry that
 * margin. Without this the white tab band sat flush against the photo's
 * bottom edge at every width, where first-party leaves a 20px/28px ivory
 * gap. Moved onto .rt-mls-tabs, same as the hero's fix, and unconditional
 * (v2's own rule is not media-gated either) since the hero always precedes
 * it in the grid, so there is nothing here for this margin to collapse
 * through. 28px override lives in the >=1024px block below, matching v2's
 * own desktop bump (rt-mls-listing-v2.css:399's block). The rail's
 * grid-row is unaffected: this only adds space, it does not add a row.
 */
body.rt-sx .rt-citypage__prose > .rt-sx-top .rt-mls-tabs { margin-top: 20px; }
body.rt-sx #rt-sx-overview, body.rt-sx #rt-sx-details, body.rt-sx #rt-mls-map-sec, body.rt-sx #rt-nearby-section {
	scroll-margin-top: 140px;
}

/* Phone: one column; the rail is a v2 desktop element (display:none below
   1024 in rt-mls-listing-v2.css). */
@media (min-width: 1024px) {
	body.rt-sx .rt-citypage__prose {
		display: grid; grid-template-columns: minmax(0, 1fr) 380px; column-gap: 28px; align-items: start;
	}
	body.rt-sx .rt-citypage__prose > * { grid-column: 1; min-width: 0; }
	/*
	 * HEADER-GAP COLLAPSE FIX (code review 2026-09-25, reproduced in a
	 * headless-Chromium fixture built from a live listing -- 123 Gauguin,
	 * Aliso Viejo -- with ShowcaseIDX actually hydrating, all three real
	 * stylesheets and rt_sx_top_html() / rt_sx_rail_html() output).
	 *
	 * This `.rt-mls-hero` margin-top used to be unconditional (declared right
	 * after the `display: contents` rule above this media query, at every
	 * width). Below this breakpoint `.rt-citypage__prose` is plain block
	 * flow, not a grid, and .rt-sx-top / .rt-mls-lower generate no box
	 * (display:contents), so .rt-mls-hero is the first IN-FLOW BOX child of
	 * .rt-citypage__prose (the address banner ahead of it is display:none,
	 * so it contributes no box either). A block's own top margin collapses
	 * into its parent's when nothing -- no border, no padding, no BFC --
	 * separates them, and nothing does here: .rt-citypage__prose carries no
	 * padding-top of its own, and the hidden address banner's embedded
	 * <style> zeroes .rt-citypage__body's ambient padding-top too (that
	 * <style> tag's rules apply regardless of the element's own display).
	 * So the 16px kept propagating straight up through .rt-citypage__prose,
	 * .rt-citypage__body and <main> to <body>, showing as a 16px strip of
	 * the site's navy body background between the fixed header and the
	 * hero -- reproduced before this fix: header bottom at y=58, everything
	 * from .rt-citypage__body down to the hero starting at y=74, both at an
	 * iPhone-13 emulation width and at a plain 900px viewport.
	 *
	 * FIX: gate the rule to this same `min-width: 1024px` block, matching
	 * the first-party v2 template, where the equivalent gap comes from
	 * `.rt-mls--v2 .rt-mls-wrap { padding-top: 16px }` (rt-mls-listing-v2.css)
	 * -- also desktop-only, and a padding rather than a margin, so it can
	 * never collapse in the first place. At >=1024px .rt-citypage__prose is
	 * a grid container, and CSS Grid never collapses a grid item's margin
	 * into the container's own margin box, so the same declaration is safe
	 * there: it only adds space inside the hero's own auto-sized grid row,
	 * which is exactly the 16px gap this rule exists to produce. Below
	 * 1024px the hero is now flush against the header with no rule setting
	 * its margin-top at all, matching the first-party template's own mobile
	 * layout (--rt-v2-hdr steps 58px -> 68px at this same breakpoint, with
	 * no 16px gap below it either). Re-verified after: hero top equals the
	 * header bottom at both the emulated and the plain 900px viewport, and
	 * the >=1024px case (hero at 84, matching v2) is unchanged.
	 *
	 * ACTIVE LISTINGS ONLY (code review 2026-09-26). The re-verify above
	 * never ran against a Sold/Closed listing, where the off-market notice
	 * (functions.php, the_content prio 47) is what actually sits FIRST below
	 * 1024px, not the hero -- this rule only ever collapses a PRECEDING
	 * margin into <body>, and it has none to collapse when the notice's own
	 * box comes first. That case has the identical collapse (the notice's
	 * own margin-top propagates up instead) and its own fix, below this
	 * media query: "CLOSED-LISTING HERO GAP + NAVY STRIP".
	 */
	body.rt-sx .rt-citypage__prose > .rt-sx-top .rt-mls-hero { margin-top: 16px; }
	/* v2's own desktop bump for the identical gap (rt-mls-listing-v2.css:399,
	   `.rt-mls--v2 .rt-mls-lower { margin-top: 28px }`), moved onto
	   .rt-mls-tabs for the same display:contents reason as the base rule
	   above. */
	body.rt-sx .rt-citypage__prose > .rt-sx-top .rt-mls-tabs { margin-top: 28px; }
	/*
	 * AUTO-MARGIN GRID-STRETCH FIX (code review 2026-09-25, verified in a
	 * headless-Chromium fixture built from the real rt_sx_top_html() /
	 * rt_sx_rail_html() markup and all three real stylesheets, at 1440px).
	 *
	 * `.rt-mls-map`, `.rt-listing-closednote`, `.rt-listing-gallery`,
	 * `.rt-listing-prose` and `.rt-listing-area` are appended as direct
	 * children of `.rt-citypage__prose` by various `the_content` filters
	 * (functions.php), and every one of them carries `margin: <top> auto
	 * <bottom>` from the listing-detail polish printer (e.g.
	 * `.rt-mls-map{max-width:1200px;margin:30px auto 0}` at (0,3,2)), a
	 * pattern written for plain block flow: width defaults to "fill the
	 * available space, then center via auto margins if max-width caps it."
	 *
	 * Once `.rt-citypage__prose` becomes a grid container at this width, that
	 * pattern breaks. Per the CSS Grid auto-margin rule, an item whose
	 * inline-axis margins are auto has those margins absorb the extra space
	 * FIRST, exactly like block-level auto-margin centering -- so the item
	 * shrink-to-fits its content instead of stretching to the grid area's
	 * width (the item never reaches the `stretch` `justify-self` this
	 * container otherwise defaults every item to, since none of them set
	 * `justify-items`). `max-width:1200px` never engages as the limiting
	 * factor either, since the grid column itself is already narrower than
	 * that. Measured live: `.rt-mls-map` rendered 348px wide (a 300px iframe)
	 * centered in its ~720px column; `.rt-listing-closednote` measured 640px
	 * wide despite already carrying `grid-column: 1 / -1` two rules above (a
	 * spanning grid AREA does not itself stretch a shrink-to-fit item to fill
	 * it); `.rt-listing-gallery` measured 451px wide before its lazy images
	 * loaded and 720px after, changing width as its intrinsic content
	 * (unset-until-loaded image dimensions) changed.
	 *
	 * FIX: zero the inline-axis (left/right) margins at higher specificity
	 * than the printer's highest (0,3,2), leaving each element's own
	 * top/bottom margin (30px, 18px, 0, 8px, 36px, 48px -- all set via the
	 * shorthand's OTHER positions) completely untouched. With the auto
	 * absorption gone, the grid's default `justify-self: stretch` takes over
	 * and each item fills its actual column width instead of shrink-fitting.
	 * `main:not(.rt-mls)` reprises the plain-SIDX-vs-first-party scope used
	 * throughout the polish printer (the first-party template's <main>
	 * carries .rt-mls; a SIDX page's never does), so this can never reach the
	 * first-party v2 template, which already lays these out correctly inside
	 * .rt-mls-wrap. Specificity (0,4,2) beats every printer rule this fixes
	 * ((0,3,2) for .rt-mls-map, (0,2,1) for the rest) outright, and none of
	 * those declarations carry !important, so none is needed here either.
	 * Re-measured after: the map iframe, closed note and gallery each fill
	 * their column/row width identically before and after image load.
	 *
	 * NOT .sidx-container, though -- correction below. This selector's
	 * "none of those declarations carry !important" is true only of the five
	 * elements it was written for (.rt-mls-map / .rt-listing-closednote /
	 * .rt-listing-gallery / .rt-listing-prose / .rt-listing-area); it does
	 * NOT hold for .sidx-container, which is ALSO a direct child of
	 * .rt-citypage__prose and so is ALSO matched by the bare `> *` below.
	 * .sidx-container's own margin-left/margin-right ARE !important (the
	 * listing-detail polish printer, functions.php: `body.rt-listing-detail
	 * .rt-citypage__prose > .sidx-container{margin-left:auto !important;
	 * margin-right:auto !important;...}`, specificity (0,3,1)), and
	 * !important always wins over a non-important declaration regardless of
	 * specificity, so this rule's margin-left:0/margin-right:0 never reaches
	 * it: .sidx-container keeps its auto margins and shrink-to-fits its
	 * content instead of stretching to the grid column (code review
	 * 2026-09-25).
	 */
	body.rt-listing-detail.rt-sx main:not(.rt-mls) .rt-citypage__prose > * { margin-left: 0; margin-right: 0; }
	/*
	 * .SIDX-CONTAINER AUTO-MARGIN / CLS FIX (code review 2026-09-25, verified
	 * in a headless-Chromium fixture built from the real ShowcaseIDX-served
	 * listing /homes/listing/CRMLS/NP26208573/1174-Winslow-Newport-Beach,
	 * hydrating, with the Task 2 parts, all three real stylesheets and the
	 * real body classes).
	 *
	 * The general `> *` rule above cannot reach .sidx-container for the
	 * reason explained in its own comment: its printer rule
	 * (functions.php:1335) carries !important, and this file's `> *` rule
	 * does not, so the printer wins the property regardless of the (0,4,2)
	 * specificity edge. During React mount the container was measured
	 * collapsing from 720px to 30px wide (centered at x=465 in its 720px
	 * column), then returning to 720px roughly 150ms later, producing two
	 * layout shifts -- desktop CLS 0.0658 on every run, on the page type that
	 * earns most organic clicks, regressing the 2026-07-16 listing CLS fix
	 * (desktop 0.000 there). The plain SIDX page and this same page with the
	 * grid removed both measure 0.
	 *
	 * FIX: a dedicated rule targeting .sidx-container directly, so its own
	 * !important wins the specificity fight outright ((0,5,2) here vs the
	 * printer's (0,3,1), both !important). Re-verified in the same fixture:
	 * CLS drops to 0 and the container stays at 720px throughout hydration.
	 */
	body.rt-listing-detail.rt-sx main:not(.rt-mls) .rt-citypage__prose > .sidx-container {
		margin-left: 0 !important; margin-right: 0 !important;
	}
	/*
	 * MAIN-COLUMN LEFT EDGES (code review 2026-09-26). Four different insets
	 * used to line up under the tabs: the hero/tabs/rail sit flush with the
	 * column edge, ShowcaseIDX's own `.sidx-main-app-body` keeps a 15px
	 * padding-left from its own vendor stylesheet, the polish-printer blocks
	 * (.rt-listing-prose / .rt-listing-gallery / .rt-mls-map / .rt-listing-area)
	 * are inset 24px (functions.php), and the legacy stats card was inset
	 * 56px. First-party's `.rt-mls-wrap` context gives every block the same
	 * flush edge; this makes the SX column do the same.
	 *
	 * `.sidx-main-app-body` is the vendor's OWN wrapper, not ours, so its
	 * padding is beaten with !important the same way every other vendor
	 * override in this file is (its source stylesheet is not in this repo to
	 * measure a specificity against).
	 */
	body.rt-sx .sidx-main-app-body { padding-left: 0 !important; padding-right: 0 !important; }
	/*
	 * The four the_content blocks are direct children of .rt-citypage__prose
	 * (same fact the auto-margin fix above relies on), each carrying its own
	 * `padding: ... 24px 0` from the listing-detail polish printer at (0,2,1)
	 * (.rt-listing-prose / .rt-listing-gallery / .rt-listing-area) or (0,3,2)
	 * (.rt-mls-map, `main:not(.rt-mls) .rt-mls-map`), none !important.
	 * Naming each class individually pushes every selector in this list to
	 * (0,5,2) (this rule's own compound selector plus the target class),
	 * comfortably clearing the (0,4,2) the map rule alone would need, so no
	 * !important is required here either -- matching the auto-margin fix's
	 * own reasoning immediately above.
	 */
	body.rt-listing-detail.rt-sx main:not(.rt-mls) .rt-citypage__prose > .rt-listing-prose,
	body.rt-listing-detail.rt-sx main:not(.rt-mls) .rt-citypage__prose > .rt-listing-gallery,
	body.rt-listing-detail.rt-sx main:not(.rt-mls) .rt-citypage__prose > .rt-mls-map,
	body.rt-listing-detail.rt-sx main:not(.rt-mls) .rt-citypage__prose > .rt-listing-area {
		padding-left: 0; padding-right: 0;
	}
	/* .rt-sx-top no longer generates a box (display:contents above), so it can
	   no longer carry its own grid-column: the hero and the nav are now two
	   SEPARATE grid items and each needs the span. Verified: hero lands in
	   row 1, nav in row 2, so the SIDX content that follows (matched by the
	   `> *` rule above) lands in row 3 -- one row later than in the original
	   (unfixed) draft of this rule, where hero+nav were still one combined
	   box occupying row 1 alone. The rail's row-start moves with it. */
	body.rt-sx .rt-citypage__prose > .rt-sx-top .rt-mls-hero,
	body.rt-sx .rt-citypage__prose > .rt-sx-top .rt-mls-tabs { grid-column: 1 / -1; }
	/* The off-market notice (functions.php, the_content prio 47) prepends
	   AHEAD of the hero on closed listings, so it is a real grid item at this
	   width too -- give it the full row or it would sit squeezed into the
	   main column alone (code review 2026-09-25). */
	body.rt-sx .rt-citypage__prose > .rt-listing-closednote { grid-column: 1 / -1; }
	body.rt-sx .rt-citypage__prose > .rt-sx-rail { grid-column: 2; grid-row: 3 / span 20; align-self: stretch; padding-top: 28px; }
	/* CLOSED-LISTING VARIANT (code review 2026-09-25, verified in a headless
	   Chromium fixture built from the real rt_sx_top_html() / rt_sx_rail_html()
	   markup): on a Sold/Closed listing .rt-listing-closednote is a THIRD
	   sibling ahead of .rt-mls-hero (row 1 = note, row 2 = hero, row 3 = tabs,
	   row 4 = the SIDX container), so the base rule above -- written for the
	   no-note case where SIDX lands in row 3 -- pins the rail one row too
	   early, overlapping .rt-mls-hero instead of aligning with the SIDX
	   content beside it. :has() gives this selector one more class than the
	   base rule (4 vs 3), so it always wins the cascade regardless of source
	   order. */
	body.rt-sx .rt-citypage__prose:has(> .rt-listing-closednote) > .rt-sx-rail { grid-row: 4 / span 20; }
}
@media (min-width: 1280px) {
	body.rt-sx .rt-citypage__prose { grid-template-columns: minmax(0, 1fr) 452px; }
}

/*
 * CLOSED-LISTING HERO GAP + NAVY STRIP (code review 2026-09-26). Two related
 * defects on a Sold/Closed listing, both below the >=1024px breakpoint (the
 * HEADER-GAP COLLAPSE fix above already re-verified the hero flush with the
 * header at 900px, but only for ACTIVE listings -- that check never ran
 * against a closed one, where the off-market note is what actually sits
 * first, not the hero).
 *
 * (1) v2's own `.rt-mls--v2 .rt-listing-closednote + .rt-mls-hero { margin-top:
 * 14px }` (rt-mls-listing-v2.css) never matches here: the note's next DOM
 * sibling is .rt-sx-top (rt_sx_top_html()'s own wrapper), not .rt-mls-hero
 * directly, and `display: contents` on .rt-sx-top does not change what a
 * sibling combinator sees through it. So below 1024px the note sat flush on
 * the hero photo with a 0px gap, the "one navy slab" look v2's rule exists
 * to prevent.
 *
 * (2) Separately, the note's OWN top margin (14px on phones, 18px from
 * 761-1023px, functions.php) was collapsing straight through
 * .rt-citypage__prose and .rt-citypage__body up to <body>, since nothing --
 * no border, no padding, no BFC -- sits between them below 1024px (the same
 * margin-collapse mechanism the HEADER-GAP COLLAPSE fix already documents
 * for .rt-mls-hero, just triggered by a different element). That painted a
 * strip of the site's navy body background between the fixed header and the
 * note.
 *
 * FIX: (1) the equivalent selector routed through .rt-sx-top, unconditional
 * (not media-gated, matching v2's own rule) so a closed listing gets the
 * same 14px at every width -- placed here, AFTER the >=1024px block's own
 * `.rt-mls-hero { margin-top: 16px }`, so equal specificity (0,4,1) resolves
 * by source order and this rule wins the tie at >=1024px too, same as v2's
 * unconditional 14px. (2) `display: flow-root` on .rt-citypage__prose below
 * 1024px establishes a new block-formatting context, which stops a child's
 * margin from collapsing through it -- the standard fix for this exact
 * problem, and safe here because .rt-citypage__prose has no margin of its
 * own that would need to collapse with anything either.
 *
 * Re-verified: gap is 14px at 390/900/1440 with the navy strip gone (the
 * probe now hits .rt-citypage__prose, not <body>); active listings are
 * unchanged (hero top 58/58/84 at the same three widths, since neither rule
 * here matches without a preceding .rt-listing-closednote); no horizontal
 * scroll; page-bottom spacing (area block to body bottom) is identical
 * before and after, since flow-root changes nothing about height, only
 * where a margin stops collapsing.
 */
body.rt-sx .rt-listing-closednote + .rt-sx-top .rt-mls-hero { margin-top: 14px; }
@media (max-width: 1023px) {
	body.rt-sx .rt-citypage__prose { display: flow-root; }
}

/*
 * "ShowcaseIDX's remaining blocks in v2 type" -- REMOVED (code review
 * 2026-09-25). Two rules used to sit here:
 *
 *   body.rt-sx .sidx-listing-description { font: 400 17px/1.7 var(--rt-f-sans), system-ui, sans-serif; color: #1a1a1a; }
 *   body.rt-sx .sidx-details-table .sidx-heading { font: 400 22px/1.3 var(--rt-f-serif), Georgia, serif !important; color: #0e2c4a !important; }
 *
 * Both lost almost every declaration to higher-specificity !important rules
 * already in the listing-detail polish printer (functions.php), and what
 * survived moved the page AWAY from v2, not toward it. Verified with a
 * headless-Chromium fixture built from the printer's exact CSS text (the
 * `.sidx-details-table .sidx-heading` rule at (0,4,1)!important, the
 * `.sidx-heading.rt-acc-hd.rt-acc-hd` accordion-header rule at
 * (0,5,1)!important, and the `.sidx-listing-description`/`.sidx-details-table
 * .sidx-heading` font-family rule at (0,4,1)!important, all beating this
 * file's (0,3,1)/(0,2,1) rules on every property except font-weight, which
 * none of the printer rules touch):
 *
 *   - Heading rule: font-size (20px General Features / 17px accordion
 *     headers) and font-family (var(--rt-f-sans)) both stayed exactly as the
 *     printer already sets them, with or without this rule present -- so the
 *     serif/22px this rule asked for never rendered. The ONE property that
 *     DID land was font-weight, because the shorthand `font:` resets every
 *     sub-property the declaration does not spell out, including
 *     font-weight, to 400 -- and nothing else in the cascade sets
 *     font-weight for these headings at a competing specificity, so this
 *     rule's 400 won outright. Measured: every SIDX section heading
 *     (General Features AND the Interior/Exterior/Community/Schools
 *     accordion headers) dropped from 700 to 400, undoing the 17px/700 the
 *     owner matched to ShowcaseIDX's own rendering on 2026-09-12 (see
 *     CLAUDE.md, "LISTING FEATURE + SNAPSHOT TYPE MATCHED TO SHOWCASEIDX").
 *   - Description rule: shrank the description from 20px/32px (line-height
 *     1.6, color #202122 -- matching the first-party v2 template's
 *     `.rt-mls-desc__body`, rt-mls-listing.css:253) to 17px/28.9px, color
 *     #1a1a1a, since nothing else in the printer competes for font-size,
 *     line-height or color on `.sidx-listing-description`.
 *
 * Deleting both restores 700-weight headings and the 20px/32px/#202122
 * description exactly, with zero effect on anything else the printer
 * already governs (font-size, font-family, margin) -- reproduced in the
 * fixture: identical output with or without the rules present, apart from
 * font-weight and the description's size/line-height/color reverting to the
 * printer's / vendor default's own values.
 */

/* .rt-mls-tourlink (a virtual-tour link, rendered inside the map section by
   realhomes_child_lseo_build_map() / inc/listing-seo-lib.php for every
   ShowcaseIDX listing that has one) is display:none above 760px in the
   listing-detail polish printer (functions.php), on the documented
   assumption that ShowcaseIDX's own .sidx-menu strip is still visible there
   with its own Virtual Tour link -- true on the plain SIDX path, but the
   hide list above removes .sidx-menu at every width, so on an rt-sx render
   there was no tour link left at all past 760px (code review 2026-09-25).
   Re-show ours: three classes (rt-listing-detail, rt-sx, rt-mls-tourlink)
   plus two elements (body, main) is (0,4,2), which beats the printer's
   (0,3,2) outright with no !important needed, so its own pinned test
   strings (tests/listing-seo.test.php) stay untouched. */
@media (min-width: 761px) {
	body.rt-listing-detail.rt-sx main:not(.rt-mls) .rt-mls-tourlink { display: block; }
}

/* Listing Snapshot table: SIDX pads its .sidx-details-table wrapper 10px,
   which set the snapshot 10px in from the description and the section
   headings (measured live: rows at 70px against a 60px column edge). The
   first-party v2 rows sit on the column edge with their own 5px cell
   padding, so zero the wrapper's horizontal padding here. Scoped to the
   snapshot: the feature accordions already zero theirs via [data-rt-acc]. */
body.rt-sx .sidx-container .sidx-listing-snapshot > .sidx-details-table {
	padding-left: 0 !important;
	padding-right: 0 !important;
}
