Space Retailing

An HTML/CSS twin of the Space Auto digital retailing widget — the embeddable tray, lead forms, vehicle search and VDP that dealership websites run for financing, trade-in, credit applications, appointments and chat, before the lead hands off to the Space CRM.

The code is the source of truth. Where this system and packages/retailing disagree, the code wins — correct the design to the code, never the reverse. This system is also separate from the Space Auto Design System (the CRM): do not reuse the CRM's tokens, names, type scale or components here, or these there.

The host contract

Read this before anything else. The widget renders inside a dealer's website, and a set of variables comes from outside it — Space sites define them at :root, external embeds write them onto the app element from dealershipConfig.branding. tokens/host-contract.css declares them with the dealership defaults this system designs against.

Nine of them — the four --primary-button-* colours, --button-border-radius (5px), --form-input-border-radius (7px), --form-input-placeholder-text-color, --form-button-text-transform (uppercase) and --font-family (Inter). Full table with defaults in readme.md.

Anything a dealer can change stays a variable. Never hard-code #3491f7 on a button, 5px on a button radius or uppercase on a CTA. The practical consequence for design work: a screen must survive a hostile brand colour — assume the primary button could be maroon with 0px radius and still have to read.

Three more host variables are read directly off the dealer's :root, outside that contract: --primary-color and --primary-button-text-color (the SRP card and VDP CTAs) and --body-font-color (VDP text). They exist so SRP, VDP and the dealer's own buttons agree on brand colour on takeover pages.

The layer map

Each layer only knows about the ones above it. Build down, not across.

Tokensstyles.css → tokens/*. Every custom property from App.module.pcss, verbatim. Light on :root, dark on .dark. Frozen — mirror values, don't add them.
Atomscomponents/{atoms,fields,choice}. Button, IconButton, Pill, Input, Select, Checkbox, Radio, SelectorButton. Everything above composes these.
Step framecomponents/layout. Container + Header + StepContainer — the frame every form screen renders through. Fill its slots; never invent a step layout.
Screenscomponents/{steps,screens,account}. The shared steps every flow reuses, plus SubmitResult, Menu and the account panels.
Tray shellcomponents/shell. TrayHeader, FooterNavigation, TriggerButton, ChatTriggerPreview, Toast, OverlayLayer. The chrome the screens live in.
Embeddedcomponents/{embedded,vdp}. What renders in the dealer's own page: embedded forms, the SRP shell and card, the VDP overlay. Where the host contract stops being theoretical.

Two things about the bottom layer. Embedded forms sit in a shadow root, so host CSS cannot reach them — the embedded search deliberately does not, because third-party SRP vendors find their mount points by scanning the document. If something looks wrong on one dealer's site and right on another, start there.

Four states

Every rule in components.css is in one of these. Canonical is the default — 539 classes. Only the exceptions are enumerated, in ENGINEER_HANDOFF.md.

CANONICAL

Mirrors shipped code. Trust it. If it disagrees with the code, that's a bug in the twin.

PRESCRIPTIVE

In the twin, not the code. One rule today: the input placeholder colour. Don't assume it ships.

DEVIATIONS

Four. Where mirroring exactly would render something broken. Build from the code.

UPSTREAM BUGS

Seven. What the code does that should be fixed. Mirrored so the two stay comparable.

The three worth knowing on day one: buttons render in the browser default font (Arial in Chrome) because the widget never resets font-family on button; --button-border-radius is undefined on external embeds, so third-party hosts get square buttons; and var(--white) text on theme-stable fills inverts in dark mode, which puts near-black text on the payment figure in ValueBox.

Three conventions

Tokens are frozen, and literals are deliberate. Use a token only when the source itself uses that token, or when the token's meaning is exactly the property being set. A value that merely happens to match a token is not a reason to use it; that is how a twin drifts while looking tidy.

All component CSS is .rt- prefixed, in one file. Several components also carry unhashed website classes (retail-lbl, dol-sign, fs-vdp-*) as the contract for per-site CSS injections and vendor scripts: don't remove them, don't style them. Icons are Font Awesome 6 Pro regular via the team kit, always an IconDefinition prop — never a glyph in text or a PNG, and no emoji anywhere.

Where to go next

readme.mdHost contract in full, visual foundations, content fundamentals, iconography, the off-scale literals table, and the VDP palette audit.
RETAILING_CODE_MAP.mdAll 539 classes: the source file each mirrors, the selector or Stack prop it came from, and the prop or config key that drives it.
ENGINEER_HANDOFF.mdThe four states enumerated, plus a "not a bug, but know about it" list of things that look wrong and are load-bearing.
Design System tabFoundations, Atoms, Templates, Screens, Shell, Embedded — every specimen card, with the source citation for each rule in its captions.

Built from Luminary-2/space-retailing @ dev, subtree packages/retailing/. Explore the repository before anything non-trivial: the widget's real component CSS carries values no specimen card can capture.