Visual Consistency — Hard Requirement
Rule
The published static site, the dashboard preview, and the client portal MUST look identical. They are the same website viewed through different delivery mechanisms.
Architecture
All three render paths use the same CSS from shared/site-css.ts:
shared/site-css.ts (CSS, NAV_CSS, CHAT_CSS, DARK_MODE_CSS)
↓ ↓ ↓
Published site Dashboard preview Portal (React SPA)
(template.ts) (SitePreview.tsx) (Portal.tsx)Published Static Site
shared/site-renderer.tsgenerates full HTML- CSS injected via
<style>tags - Served from GCS as static
.htmlfiles
Dashboard Preview
SitePreview.tsxcallsrenderLandingPage()from shared- Injects the resulting HTML + CSS into a scoped container
- Navigation intercepted via React click handlers
Client Portal
Portal.tsximportsCSS,NAV_CSS,getThemeCss()from shared- Injects the same CSS via
<style>tags - Uses the same CSS class names (
.header,.site-nav,.chat-btn,.footer, etc.) - Theme and color mode applied from business settings
When Adding New Styles
- Add CSS to
shared/site-css.ts - Use the class names in
shared/site-renderer.ts(for published site + preview) - Use the same class names in
Portal.tsx(for portal) - Never add Tailwind classes in Portal.tsx for elements that should match the published site — use the shared CSS class names instead
When Adding New Sections
- Add HTML generation to
shared/site-renderer.ts - The preview automatically picks it up (same renderer)
- If the section needs to appear in the portal, use the same class names in Portal.tsx
Themes and Dark Mode
- Themes are CSS variable overrides from
getThemeCss()inshared/site-helpers.ts - Dark mode is from
getColorModeCss()— returns CSS + a JS snippet - All three paths apply these the same way
- The portal receives
themeandcolorModefrom/api/portal/resolve
Testing Consistency
Before shipping changes to the website template:
- Check the published site (republish)
- Check the dashboard preview (Website tab)
- Check the portal (
/portal/{slug}) - Check a portal sub-page (
/portal/{slug}/{page}) - Check mobile view in all three
If any of these look different, the change is not ready.