# plain-css adapter — second-adapter smoke (WHYNOT-WP-0002 · T10) > **This is not a finished stack.** It exists to prove the **IR/adapter boundary**: > that a second, non-Lit adapter can consume the *same* `ir/` and honour the *same* > [`adapters/ADAPTER_CONTRACT.md`](../ADAPTER_CONTRACT.md). The deliverable is > confidence in the seam, so the architecture can later be lifted into a > coulomb-level tool — **not** a usable plain-CSS component kit. Run with **`make adapt-plain-css`** (`adapters/plain-css/adapt.mjs`). ## What it proves | Contract concern | This adapter | Same as Lit? | |---|---|---| | Input is `ir/` only | reads `ir/tokens.json` + `ir/components/*.json` | ✓ identical inputs | | Tokens fully generated | → `adapters/plain-css/tokens.css` (CSS custom properties, deterministic no-op re-run) | ✓ same discipline, different target | | New component → stub | write-once class stub `adapters/plain-css/stubs/.css` (base + variant modifier classes from the contract) | ✓ write-once, into a staging dir | | Drift roll-up | `adapters/plain-css/_report.json` in the contract's report shape (`stack`, `generatedAt`, `components[]`) | ✓ portable shape | | Exit codes | `0` ok · `2` usage · `3` new/drift · `5` internal | ✓ shared convention | Because plain-CSS has no hand-authored source, **every** IR component reports `status: "new"` and gets a stub — exactly the contract's new-component path. That a totally different stack reuses the same IR, the same report shape, and the same exit codes — with **zero changes to `ir/`** — is the proof the boundary holds. ## What it deliberately does NOT do No real CSS appearance, no parity, no full component set, no integration into the repo's build. Finishing a plain-CSS (or Vue/Svelte/…) stack is future work; the seam is what T10 validates. See `DesignSystemIntroduction.md` §5.1 and the Lit reference adapter (`adapters/lit/`) for the full implementation.