Appearance
Theming
The widget renders into an open shadow root, with :host { all: initial }. Your stylesheet cannot reach inside it, and nothing inside it can leak out onto your page. The one channel between the two is a set of CSS custom properties set on the host element.
Most of the time you do not need to use it: the SDK samples your page first.
What is sampled
On takeover, the SDK reads the computed style of your first non-choice field, your form and your submit button:
| Token | Sampled from | Fallback |
|---|---|---|
--nam-font | the field's font-family, else the form's | system-ui, -apple-system, "Segoe UI", sans-serif |
--nam-font-size | the same source's font-size | 16px |
--nam-fg | the field or form color, if opaque | #1f2937 |
--nam-bg | the nearest opaque background-color walking up from the form | #ffffff |
--nam-border | the field's border-top-color | #d1d5db |
--nam-radius | the field's border-top-left-radius | 8px |
--nam-accent | the submit button's background-color | #2563eb |
--nam-accent-fg | the submit button's color | #ffffff |
Four more are derived from that pair rather than sampled, so a dark host page gets dark surfaces instead of pale grey ones:
| Token | How | Fallback |
|---|---|---|
--nam-muted | foreground blended toward background until it clears 4.5:1 against the background | #6b7280 |
--nam-bubble | foreground blended into background until text on it clears 4.5:1 | #f3f4f6 |
--nam-dark / --nam-on-dark | the sampled pair, inverted — a sheet cover is the page turned over | #1f2937 / #ffffff |
--nam-accent-soft | accent blended toward background, else --nam-bubble | #eff4ff |
A bad pair is left alone
If the sampled foreground and background do not themselves reach 4.5:1, nothing is derived and the known-good defaults are kept. A blend of an unreadable pair is only unreadable twice.
Overriding it
data-nam-theme takes a JSON object of custom properties, merged over the sampled set:
html
<form
data-nam-landing-page="kestrel"
data-nam-key="lp_live_xxxxxxxx"
data-nam-theme='{"--nam-accent":"#e8862b","--nam-display-font":"Fraunces, serif","--nam-image-position":"center 30%"}'
>Only string values whose keys look like --a-custom-property survive parsing. Malformed JSON, an array, or an empty result all yield null and the sampled theme is used unchanged — silently, which is why a theme that "did not apply" is almost always a quoting problem.
Escape inner single quotes
The JSON needs double quotes, so the attribute has to use single ones. A single quote inside the JSON — a font name like 'DM Sans' — truncates the attribute there, and the browser scatters the remainder as bare attributes. Write it as '.
Tokens you can only set here
These are never sampled. They exist for the cases the page has to decide.
| Token | Default | What it controls |
|---|---|---|
--nam-image-position | center | The object-position of every picture the SDK draws — answer tiles, option cards, sheet covers. Takes any CSS object-position, e.g. center 20%. |
--nam-thread-max | min(60vh, 520px) | The inline thread's maximum height before it scrolls. Ignored in panel layout, which is already full height. |
--nam-display-font | var(--nam-font) | Headings on question units, cards and sheets. Set it to give the experience your display face. |
--nam-surface | var(--nam-bg) | The background behind stage blocks. |
--nam-gap | 12px | The global spacing rhythm. |
--nam-ink | a 55% mix of --nam-border | Every hairline border. |
--nam-lift | a soft teal-neutral drop shadow | Bubble and card elevation. |
About the crop
Every image is object-fit: cover into a wide box — roughly 2.9:1 for an answer tile and 4.4:1 for an option card — so it keeps the middle band of whatever it is given. Portrait photography with faces high in the frame renders as headless torsos.
--nam-image-position moves that crop, but it moves it for every picture on the page at once. It works well for a photography library shot consistently; where the art varies — a full-length shot beside a close-up — cut the art to the shape instead. There is no per-image control, and the host stylesheet cannot supply one.
Class names inside the shadow root
The rendered markup uses nam-* classes and a set of data-nam-* hooks, listed in the attribute reference. They are stable enough to write an end-to-end test against and are not a supported styling channel: your CSS cannot reach them, and they are free to change with the bundle.