# Styles Source: [Styles](https://typeroll.com/docs/tools/styles/) > Named, reusable styles for text, headings, buttons and sections — set once, used everywhere, with readable contrast enforced. A site’s look is a library of **named styles**. You create them, name them in your own words (“Överrubrik”, “Hero title”, “Price note”) and reuse them. Change a style once and every page using it follows. There are two kinds: * **Site-wide styles** for body text, Heading 1–6 and links. They apply to every matching element automatically, on every page. * **Styles chosen per block**, such as an eyebrow, a lead paragraph, a quote, a button or section spacing. Pick them in a block’s **Style** field. See [Design tokens](https://typeroll.com/docs/guides/design-tokens/) for palette-first block fields, named scales, auditing and migration (prepared for Core 0.2.106). ## Start with the standard styles New sites start with a considered standard set: body text, Heading 1–6, link, lead, eyebrow, small text, quote, primary and secondary button, and section spacing. Sizes and spacing are set for phones, tablets and desktops. Setting these to match the brand is the natural first step of a new site, before building pages. For an existing site, **Styles → Add standard styles** adds the ones it is missing and never changes styles you already have. ## Edit a style Open **Styles** in the site menu. Each style has: * **Name** and **When to use it**, which editors and AI agents see. * **Class**, a stable id (`s-`) for custom CSS. It cannot change later. * **Can be chosen for**: text, headings, lists, buttons, sections and containers, links or images. Links and images are chosen for [block parts](https://typeroll.com/docs/tools/styles/#style-parts-of-a-block), such as the links in a formatted heading or a hero’s image. * **Block parts**: parts of blocks this style applies to on every block of that type (see [below](https://typeroll.com/docs/tools/styles/#apply-a-style-to-a-part-on-every-block)). * **Values per screen size.** **Mobile** applies everywhere. **Tablet**, **Laptop**, **Desktop** and **Wide** override from that width up. An empty field keeps the smaller screen’s value, shown as a hint. * Font, size, weight, line height, letter spacing, case, italic, text and background colour, alignment, underline, spacing before and after, padding, max width, corner radius, border, opacity, shadow and gap. * **Advanced CSS**, scoped to the style: bare declarations, or rules where `&` stands for the style, such as `&::before { content: "—" }`. | Property | Values | | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `opacity` | A number from `0` (invisible) to `1` (opaque), such as `0.8`. | | `shadow` | `none`, `sm`, `md` or `lg`. `none` removes a shadow the block draws itself, such as the inset ring of an outline button. | | `gap` | Space between the children of a flex or grid element: one length (`1rem`), or row and column (`1rem 2rem`). Useful for a block’s layout parts, such as a hero’s row of buttons. | The preview shows the style at the selected screen width with the site’s own colours. Fonts load on the site itself. Colours are best chosen from the palette (primary, secondary, accent, background, surface, text, text light). A palette change then flows through every style. `on primary`, `on secondary` and `on accent` are the text colour on that palette colour: the site’s own choice when one is set (see [Text on theme colours](https://typeroll.com/docs/tools/settings/#text-on-theme-colours)), else black or white, whichever reads better. ## Site-wide link hover The `link` role supports `hover`, for example `{ "color": "primary", "decoration": "underline" }`. It generates a normal `a:hover` rule for links throughout the site, including prose, breadcrumbs, the table of contents and the consent dialog’s privacy link. More specific block and part hover rules (buttons, navigation and cards) retain precedence. No hover values means no additional hover rule. Palette names are supported. Available from Core 0.2.121. Existing static sites need to be published again after upgrading. Touch-only devices do not have a persistent mouse hover state. ## Readable text Every style’s text is measured against its background at every screen size, including hover colours, with two measures: * **APCA** (Accessible Perceptual Contrast Algorithm, APCA-W3 0.0.98G-4g), a lightness contrast `Lc` that models how people perceive brightness and polarity. It decides. * **The WCAG 2 contrast ratio**, which WCAG 2.x AA conformance (and EN 301 549) uses: 4.5:1, or 3:1 for large text (24px, or 18.7px bold). The WCAG 2 ratio overrates dark text on mid-dark saturated colours. On teal `#00a19c`, `#111827` is 5.56:1 but APCA Lc 44, while white is 3.19:1 but Lc 63.9, and white reads better. The APCA level a text needs depends on how it is read, its size and its weight. Typeroll uses the [APCA Readability Criterion](https://readtech.org/ARC/) Bronze levels, with the size and weight minimums of the APCA guidance for non-body text: | Text | APCA Lc | | --------------------------------------------------------------------------- | ------- | | Body text: body, lead, quote, link and section styles; text and list styles | 75 | | Secondary text: the small text style (notes, captions, fine print) | 60 | | Headings, eyebrows and buttons from 16px at weight 600, 21px at 500 or 24px | 60 | | Headings, eyebrows and buttons from 24px at weight 700, or 36px | 45 | | Smaller or lighter headings, eyebrows and buttons | 75 | Body text under 14px, and any text at weight 300 or lighter, needs the next level (Lc 15 more, up to 90). A style without a standard role counts as a heading or button only when it can be chosen for headings and buttons alone. Sizes are read from the style (px, rem or em); without a size, 16px is assumed, and without a weight, 400 (700 for headings). Lc is compared after rounding to a whole number. * **Refused:** text that misses its APCA level and WCAG 2 AA. Light grey on white is never accepted. * **Saved with a warning:** text that misses its APCA level but meets WCAG 2 AA. Every style accepted before APCA stays accepted. * **Accepted:** text that meets its APCA level, such as white 16px semibold button text on `#00a19c`. Its WCAG 2 ratio can be lower than 4.5:1: a site that must conform to WCAG 2.x AA should keep that ratio, shown next to each colour in Settings and in every message. Messages give both measures, for example “`#111827` on `#00a19c` is APCA Lc 44.0, WCAG 2 5.56:1”. The API and MCP return warnings as `warnings`. When standard styles are added to a site whose palette colour is unreadable on the background (it fails both measures), those styles use the body text colour instead, because adding them unchanged would be refused. The result lists them in `adjusted` and says in `warnings` which colour was replaced and why, with both measures. Existing styles are never changed. ## Apply a style to a block Heading, formatted heading, text, list, button, section and container blocks have a **Style** field (**Heading style** on a heading) listing the styles made for that kind of block. Choose **Default look** to use the block’s own appearance. A heading’s eyebrow and subtitle have their own style fields; left on **Site default**, they use the site’s Eyebrow and Lead styles (render version 2). The style is applied to the meaningful element: the `

` in a heading block, the link in a button. A chosen style wins over the block’s own default appearance for the properties it sets. Note A heading’s level (H1–H6) describes the document structure. Its look comes from a style. A small label above a heading is usually an **Eyebrow** style, not a heading of its own. ## Style parts of a block Blocks draw some of their elements with a fixed look of their own: the underline on links in a formatted heading, the size of a hero’s heading, the corners of its buttons. A **part** is such an element, named on the block type: `link` in a formatted heading, `heading`, `primary_button` and `media` in a hero. A style can be given to a part, so you change that look with a named style instead of CSS against the block’s markup. Each part has a kind, and only styles that can be chosen for that kind are offered: a link part takes link styles, a hero’s image takes image styles. The parts of the core blocks are listed in [Block parts](https://typeroll.com/docs/tools/blocks/parts/#block-parts); `read_block_type` lists the parts of any block type. ### Apply a style to a part on one block Select the block and open **Appearance → Part styles**. Each part has a picker with the styles of its kind; **Site default** keeps the site-wide style for the part (named in the option when there is one), or else the block’s own look. Through MCP or the API, set the block’s `part_styles` field, a map from part name to style id: ```plaintext update_block page_id=… block_id=… data={ part_styles: { link: "quiet-link" } } ``` `update_block` replaces the whole map, so send every part you want to keep; `null` removes it. A heading’s eyebrow, heading text and subtitle, and a button’s link, are parts too, but they keep their own style fields (`eyebrow_style_id`, `style_id`, `subtitle_style_id`) instead of `part_styles`. ### Apply a style to a part on every block In a style’s **Block parts**, tick the parts it applies to, for example **Formatted heading · Links**. The list shows the parts of the kinds the style can be chosen for, grouped by block, and says which other style already holds a part. Through MCP or the API it is the style’s `parts`, as `.`: ```plaintext create_style id="quiet-link" name="Quiet link" targets=["link"] base={ decoration: "none" } parts=["core/rich_heading.link"] ``` A part takes one site-wide style. The style’s **Can be chosen for** must include the part’s kind, and a part the site’s block types do not have is refused with the closest part names. Element roles (body, Heading 1–6, link) already style every matching element and cannot list parts. `update_style` replaces `parts`; `[]` or `null` removes the style from every part. ### Which style wins From lowest to highest: 1. The block’s own look, including its field values. 2. The default role style, such as the site’s Eyebrow style on an eyebrow. 3. The part style: the block’s own **Part styles** choice, else the site-wide style for the part. A block’s choice replaces the site-wide style entirely; nothing of the site-wide style remains on that block. 4. A style class on the element itself: a heading’s eyebrow style, a button’s style, or a paragraph style from the text editor. A part style sets only the properties it has values for. It wins over the block’s own fields for those properties, as a chosen style always does: to look different on one block, choose another style for the part there. ### Readable parts A part style’s text is measured against the part’s background with the same APCA and WCAG 2 levels as other styles. The background is the block’s own background colour where the block has one (a hero’s **Background**), the colour the block paints behind the part (a primary button on primary), or else the site background. Parts without text of their own, such as a hero’s overlay or button row, are not measured. * Choosing a style for a part on one block is refused when its text fails both APCA and WCAG 2 AA there (`part_style_contrast`), and saved with a warning when it misses only its APCA level. * A style that lists parts is measured on each part’s background when it is saved. ## Styles and custom CSS Site-wide body, heading and link styles set variables that the platform’s own CSS reads. Other styles are classes (`s-`). Write custom CSS against those classes instead of platform internals such as `[data-block]` or `.block-*`, which can change between render versions. To change an element a block draws itself, such as the underline on a formatted heading’s links, give its [part](https://typeroll.com/docs/tools/styles/#style-parts-of-a-block) a style instead. ## Site CSS and page CSS For what styles cannot express, there are two managed CSS fields: * **Site CSS** (Styles → Site CSS, admins) loads on every page after the styles. Through MCP or the API it is `custom_css` in `update_site_settings`. * **Page CSS** (page editor → page settings → Page CSS) loads after the site CSS on that page only, and saves with the page draft. Through MCP or the API it is `custom_css` on `update_page`. Both editors check the CSS as you type and show line numbers: * **Errors** prevent saving: unbalanced braces, an unclosed comment or string, declarations outside a rule, `expression()`, `javascript:` URLs and anything that would end the stylesheet early. The API refuses the same writes. * **Warnings** allow saving: selectors on platform markup such as `[data-block]` or `.block-…`, which can change between render versions, and `@import`, which delays the page. The API returns them as `warnings` (settings) or `css_warnings` (pages). The editors offer the site’s style classes and the CSS classes set on the page’s blocks as selectors to insert. Prefer them: `.s-eyebrow` or `.pricing-note` keeps working when platform markup changes. ## Through MCP and the API | Tool | REST | Purpose | | ----------------------- | --------------------------------------------- | ------------------------------------------------ | | `list_styles` | `GET /api/v1/sites/{siteId}/styles` | The library, missing standard roles and problems | | `create_style` | `POST /api/v1/sites/{siteId}/styles` | Create a style | | `update_style` | `PATCH /api/v1/sites/{siteId}/styles/{id}` | Update; properties merge, `null` removes one | | `delete_style` | `DELETE /api/v1/sites/{siteId}/styles/{id}` | Delete; blocks fall back to their default look | | `apply_standard_styles` | `POST /api/v1/sites/{siteId}/styles/standard` | Add missing standard styles (`overwrite` resets) | Set a block’s style with its `style_id` field, for example `update_block … data: { style_id: "eyebrow" }`, a part’s style on one block with `data.part_styles`, and a part’s style on every block with the style’s `parts` (see [Style parts of a block](https://typeroll.com/docs/tools/styles/#style-parts-of-a-block)). Styles are versioned with the site settings, so a branch can try new styles without changing the live site. AI agents follow the same rule as people: a look that could recur becomes a named style, and only a clearly unique one-off uses block settings. Heading roles (`h1`–`h6`) support `space_before` and `space_after` at the base and at each style breakpoint. Use these for consistent vertical rhythm, rather than adding a spacer to every page. Whole-tree writes check global part styles as well as per-instance styles against known ancestor background colors. These checks do not replace browser review of images, gradients or custom CSS.