Style What You Publish: Catalogs Get A Presentation Contract
The platform renders catalog pages; until now an application could recolor exactly three things. This entry
records the presentation contract that ends that: every visual decision in the renderer reads a
--kdcpub-* design token, and an application overrides tokens or loads its own
stylesheets — declared in its config, per alias and per fold. The platform keeps structure, SEO, and
behavior; the application owns the look. Worked case: our own /blog and /news.
Public content made app data discoverable; catalogs gave each content set a browsable face. This entry records the next boundary we had to draw: who owns how those pages look. The answer is a presentation contract — the platform renders the structure, the application declares the look: design tokens and its own stylesheets, straight from its config.
The forcing observation came from a design review. The catalog renderer lived in the SDK with its styling baked in, and an application could configure exactly three colors per fold. That is a recolor, and a generic platform feature deserves more: one team wants a serif editorial masthead, another wants their product's sans and a tighter column, a third replaces the row treatment entirely. All of them should get there from config, with the platform still owning everything a listing page must do correctly.
The platform owns STRUCTURE routing, canonical URLs, sitemaps, pagination,
search semantics, accessibility, the HTML
anatomy, stable kdcpub-* class names — and a
neutral default theme.
The application owns LOOK design tokens (colors, fonts, radii, widths)
and whole stylesheets, declared per alias in
its config; folds may override per catalog.
Every visual decision is a token
The renderer's stylesheet no longer contains a single hardcoded brand decision. Everything it draws reads a
--kdcpub-* CSS variable — page and surface colors, text inks, the accent family, the body font,
the display font, radius, content width. The defaults form a tasteful, unbranded theme; an application
overrides any of them under presentation.theme:
public_content:
blog:
presentation:
theme:
display: "'Fraunces',Georgia,serif" # masthead / empty-state font
ink: '#0D1E2C'
width: 1180px
Tokens merge in a fixed order, later wins:
SDK defaults ← alias presentation.theme
← fold accent/background/border shorthands
← fold presentation.theme
The three per-fold color shorthands that existed before are unchanged — they are simply token writes now.
And when an override changes accent alone, the derived values (accent_rgb for
transparent tints, accent_dark for hovers) follow automatically, so one hex still recolors a
whole fold coherently.
Token values are sanitized at config resolution: a value that could escape a style block fails the alias configuration outright. A page is never served half-styled.
Stylesheets load after the platform's
Tokens cannot load a webfont or restructure a component. For that, the application declares stylesheet URLs — its own public assets — and the platform emits them after its own styles and the token block:
1. <style> SDK structural styles (all var-driven)
2. <style> :root { --kdcpub-* } resolved tokens
3. <link> alias presentation.stylesheets, in declared order
4. <link> fold presentation.stylesheets, appended
The application's CSS therefore wins the cascade at equal specificity, and the namespaced
kdcpub-* classes are the stable selector contract — masthead, fold control, search, rows,
pagination, empty state, chrome, rail. Item pages under a catalog carry the same presentation automatically.
One rule keeps configs honest: a stylesheet is an asset with a URL. The config carries intent — tokens and links — never CSS bodies.
public_content:
blog:
presentation:
stylesheets:
- https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,500;9..144,600&display=swap
- /assets/pub-brand.css
theme:
display: "'Fraunces',Georgia,serif"
The worked case: our own catalogs
The first consumer is the surface you may be reading right now. Our site's landing page moved to an editorial language — compact masthead, segmented controls, full-width hairline-divided article rows, restrained teal on pale mint. The catalog renderer's default structure was redesigned to that editorial system, while its defaults stayed neutral — the serif display stack in the SDK is plain Georgia.
The KDCube look is then just our own presentation block: the blog and news
aliases load Fraunces via a stylesheet URL and set one display token. Five folds keep their
distinct color worlds (navy, teal, gold, blue, pink) through the same shorthands as before; empty folds get a
deliberate centered empty state; search and pagination stay quiet and fold-scoped.
Field notes
- Do the boundary before the beauty. The original task was "make the catalogs match the landing page". Doing that directly would have baked one brand into a generic renderer and made the next application's restyle a code change. Settling ownership first turned the redesign into the default theme of a contract.
- Neutral defaults, branded config. The platform's out-of-the-box look must be presentable and unbranded; anything with a brand name in it — a webfont, a palette — belongs in the application's presentation block.
- Presentation is paint. Nothing in the contract can change routes, canonicals, sitemap output, search semantics, or pagination behavior — and the public header stays anonymous: it renders the links the config declares and carries no identity scripts.
- Derived values need an escape hatch. Deriving tints from the accent is right for the common case, but both derived tokens accept explicit overrides for the palette that breaks the darkening heuristic.
- Full replacement is a later chapter. The token + stylesheet surface covers restyling. Replacing the page layout wholesale would be a renderer protocol — designed, documented as out of scope, deliberately not improvised through CSS.
Documentation on GitHub
The live docs behind this entry: