When a source element's styling classes can't all map to native options — like a text logo's font-serif / tracking-tight / hover:text-primary — how should the converter translate them, and does the rule apply to chrome as well as content?
The question. A source logo is a text wordmark:
<a class="font-serif text-2xl md:text-3xl tracking-tight text-foreground hover:text-primary …">Maison</a>.
The converter captured the text, colour, size and weight — but the output rendered "Maison" in the
theme's sans default, with none of the source's serif, tight tracking, or hover colour. So: when
an element's classes can't ALL map to native options, how should we translate them — and does the
rule we adopted for content sections apply to chrome (logo / header / footer) too?
Context. Earlier we adopted a strict "never-drop" rule for content: a class that maps to no
native option is carried as scoped :where(selector) custom CSS rather than dropped, enforced by a
parity gate that fails on any visually-significant dropped class. But that rule lived on the content
path. The chrome converters (logo/menu/footer → Theme-Settings values) had their own, older
mapping that captured some properties (the logo took colour/size/weight) and silently dropped the
rest (font-family, letter-spacing, hover). The logo_custom_css residual channel even existed — it
was used for the two-tone accent colour — but nothing routed the wordmark's font/tracking/hover
through it. So the never-drop principle was real for content and only partial for chrome.
Options considered.
- Patch the logo only. Add font-family/letter-spacing/hover to
detect_logo. Pro: fixes the reported case fast. Con: leaves the same gap on menu links, footer headings/links, and the tagline; we'd re-discover it element by element. - Carry the whole raw class string onto the element. Rejected: Tailwind utilities are dead in the builder (no runtime), so the classes do nothing; and it forfeits the editable native options.
- One uniform three-tier translation for every element — and extend the QA gate to chrome.
Per property: (1) a native option if the target exposes one (editable, clean); (2) a design
token / preset for brand values (a colour → the Color Preset var, a face → a loaded font); (3)
scoped custom CSS as the never-drop last resort (
logo_custom_css, a section'scustom_css, the header/footer custom-CSS layer). Then extend the dropped-class parity gate so it audits chrome elements' source classes, not just content builder nodes — so the remaining gaps surface by evidence instead of guesswork.
Decision. Option 3. The translation procedure is the same everywhere: native option →
design token/preset → scoped custom CSS (never dropped), applied to chrome exactly as to content.
Concretely for the logo: font-family (font-serif) and letter-spacing (tracking-tight) have no
native logo option, so they're carried as scoped .site-title-text{…} in logo_custom_css; the
hover class (hover:text-primary, invisible to computed :hover) is read as a semantic token and
mapped to the theme's Color-Preset var (.site-title a:hover .site-title-text{color:var(--color-primary)})
— portable and editable, not a hard-coded hex. Only a distinctive font family (serif/mono/display or
a named font) is carried, so a plain system-sans stack that already matches the theme body isn't
needlessly overridden. Mirrored in both converter engines (PHP detect_logo + JS
capture-extract / to-theme-settings).
Why. The bug wasn't "the logo mapper missed a field" — it was that the never-drop rule was scoped
to content while chrome kept an older, lossier mapping. Fixing only the logo would leave menu links
(uppercase / tracking-[0.15em] / hover) and footer typography with the identical gap. Making the
three-tier procedure uniform means one rule to reason about, and extending the QA gate to chrome
turns "which classes are we still dropping?" into a measured list rather than a hunt — the same way
the content gate already catches dropped width utilities. The token tier matters specifically for
brand values: routing the hover through var(--color-primary) keeps the logo consistent with the
rest of the converted palette and editable from Theme Settings, where a captured hex would silently
drift. Verified on a real convert: "Maison" now carries font-family:"Cormorant Garamond", …, serif; letter-spacing:-0.75px and a primary-coloured hover, matching the source; golden fixture holds
(348/0). The remaining chrome targets (menu-link transform/tracking/weight/hover, footer
heading/link skin, tagline) are the next applications of the same rule, found via the extended gate.
