Every other embedded surface portals into a shadow root. This one deliberately does not, and the source explains at length why: third-party SRP integrations — TradePending, CapitalOne, CarGurus — locate their mount points by scanning the document, and a scan cannot pierce a shadow boundary, so light DOM keeps the website's vendor mechanics working verbatim. The consequence matters for design: host CSS cascades into this surface. Isolation is only hashed class names plus a scoped reset, which is why the stylesheet opens by pinning box-sizing on the wrapper and every descendant and zeroing margins on h1–h6 and p — the highest-risk bleed from dealer themes. If something looks wrong on one dealer's site and right on another, start here.
A ResizeObserver in EmbeddedSearch/index.tsx writes three custom properties onto the shell element. --srp-shell-height is window.innerHeight − the shell's own offsetTop, floored at 480px — the floor exists so a host that mounts the SRP below the fold, or in a too-short slot, gets a full-viewport shell instead of a letterbox. --srp-topbar-height is the results top bar measured live, because on mobile that bar becomes two stacked rows and its height is no longer the 60px token. --srp-mobile-toolbar-height is the HOST theme's fixed bottom toolbar (.mtb-v2-wrapper or .global-bar-mobile) — the widget measures someone else's furniture so the apply CTA and the last results row can clear it. Two deliberate non-behaviours: the observer runs on resize only, never on scroll (re-measuring as the host header scrolls away would grow the shell by exactly what the page scrolled — an endless scroll treadmill), and it only writes on change, because the shell and the top bar are its own observation targets and an unconditional write would feed it a second measurement. Only --srp-trim-color (gray-6) and --srp-top-height (60px) are plain CSS.
Desktop is an app shell one viewport tall: a 240px rail column, the results taking the rest. The shell itself never scrolls — the rail and the results toolbar hold position and the two panes scroll independently, each with overscroll-behavior: contain so a wheel reaching either end does not chain out and scroll the dealer's page underneath. The results toolbar is a sibling of the scroller rather than a sticky child, which the source notes means it cannot move at all and needs no background mask. Below 767px the rail becomes a bottom sheet: translateY(100%) → 0 over 0.25s, pinned from --srp-topbar-height to the bottom, with its own header hidden because the results top bar owns the toggle. The Show N vehicles button appears only when the sheet is open and is margined up by the host toolbar's measured height — and the source flags that it is not position: fixed, because the open panel's transform would make fixed resolve against the panel. Note visibility transitions with a 0.25s delay on close so the slide-down is seen before it is hidden. The grid's minimum column is 300px, rising to 340px at 768px, with --gutter (16px) serving as both gap and outer padding.
This is the most host-coupled component in the widget, in three separate ways. (1) It reads the dealer's own brand variables directly: the primary CTA is background: var(--primary-color, var(--primary-accent)) with color: var(--primary-button-text-color, var(--white)) — note those are NOT the host contract's --primary-button-color; they are a fourth and fifth host variable read only here, and the source says why: it is the same bridge the VDP's .btn-primary uses, so SRP cards and the VDP agree on brand colour on takeover pages. (2) Three variables arrive as inline values: --retail-label from config.priceLabel (the MSRP label is an empty span whose word comes from CSS, so per-site .retail-lbl:before injections keep working), and --ext-color / --int-color from vehicle data, painting the 135° split colour disc. (3) The DOM carries unhashed website class names — vehicle, vehicle-title, retail-lbl, dol-sign, vdp-link — as deliberate, unstyled hooks for Command Center per-site CSS injections and vendor scripts, alongside a full set of data-* attributes. Do not remove them; do not style them either.
Price text nodes carry the number only. The $, Save $, Save …% and Incentive(s) are all CSS content, ported from srp-v5.css so the DOM text and the visible text both match the website — which also means the singular/plural of "Incentive" is a [data-count='1'] rule, not a JS branch. The price is 18px / 700: the only 700 weight anywhere in the widget, and since Inter loads 400/500/600 it renders as a synthesised bold. CTA hover is opacity 0.9 rather than a colour change, because the fill may be any dealer colour — the same reason the card's own hover is a shadow. Tag badges are a hard-coded #e0f634 at a 24px radius, in no token and the only pill radius in the system. The whole card is clickable via an absolute link at z-index 1 with every interactive child lifted to z-index 2. And the CTA's radius falls back twice: var(--border-radius, var(--button-radius)), at a 40px min-height that is off the 32/48/64 control scale.