Norq
Spec/0.1-alpha/cascade

Attribute Cascade Spec

Defines conformance examples for the attribute resolution order. The canonical cascade is documented in brand.md § 9. In short (highest priority first):

  1. Inline attrs ({key="value"} on the element)
  2. Template frontmatter brand: partial override
  3. Named styles ({.name})
  4. Per-component defaults (brand.defaults.<type>)
  5. Compiler inference (e.g. images in flush sections, text in dark bg)
  6. Brand theme tokens (colors, typography, including element-typography)
  7. Built-in compiler defaults

The key words MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD, SHOULD NOT, RECOMMENDED, MAY, and OPTIONAL in this document are to be interpreted as described in RFC 2119 and RFC 8174 when, and only when, they appear in all capitals, as shown here.

The cascade described here applies to block-level attributes ({key="value"} on directives, headings, and inline blocks). Push frontmatter platform keys (ios:, android:, web:) follow a separate interpolation rule — see push.md § Frontmatter interpolation. Implementations MUST interpolate string values inside those blocks against runtime data; non-string scalars MUST pass through unchanged.

Per-Component Defaults

The brand.defaults: block in frontmatter sets default attributes for element types. These MUST be applied automatically to every instance of that element type unless overridden by inline attributes, named styles, or compiler inference (in that resolution order). The same shape lives at defaults: in brand.yaml itself; the per-template frontmatter override nests under brand: to keep one canonical vocabulary.

Image defaults

---
subject: Test
brand:
  defaults:
    image: { padding: "0" }
---
 
![Hero](https://example.com/img.jpg)
.
<mj-image src="https://example.com/img.jpg" alt="Hero" padding="0px" border="none" />

Button defaults

---
subject: Test
brand:
  defaults:
    button: { borderRadius: "0" }
---
 
[Click](https://example.com){button}
.
border-radius="0px"

Inline attrs override defaults

---
subject: Test
brand:
  defaults:
    image: { padding: "0" }
---
 
![Hero](https://example.com/img.jpg){padding="spacious"}
.
padding="40px 32px"

Named Styles

The brand.styles: block defines named attribute bundles applied via {.name}. Same authoring shape as styles: at the brand.yaml root.

Basic style application

---
subject: Test
brand:
  styles:
    headline: { size: "4xl", weight: "bold", align: "center" }
---
 
THE WAIT IS OVER
{.headline}
.
font-size:36px
.
font-weight:700
.
text-align:center

Style composability

Multiple styles MUST merge left-to-right. The later style MUST win on conflicts.

---
subject: Test
brand:
  styles:
    big: { size: "4xl" }
    centered: { align: "center" }
---
 
Hello
{.big .centered}
.
font-size:36px
.
text-align:center

Inline attrs override styles

---
subject: Test
brand:
  styles:
    headline: { size: "4xl", align: "center" }
---
 
Hello
{.headline size="sm"}
.
font-size:14px
.
text-align:center

Styles above defaults in cascade

---
subject: Test
brand:
  defaults:
    text: { align: "left" }
  styles:
    centered: { align: "center" }
---
 
Hello
{.centered}
.
text-align:center

Compiler Inference

Padding propagation — images in flush sections

Images inside a section with padding="none" inherit zero padding.

---
subject: Test
---
 
::: columns {padding="none"}
::: col
![Hero](https://example.com/img.jpg)
:::
:::
.
padding="0"

Override still works:

---
subject: Test
---
 
::: columns {padding="none"}
::: col
![Hero](https://example.com/img.jpg){padding="spacious"}
:::
:::
.
padding="40px 32px"

Dark background text color

Text in dark background sections defaults to white.

---
subject: Test
---
 
::: columns {bg="#000000"}
::: col
Hello dark world
:::
:::
.
color:#ffffff

Explicit color overrides inference:

---
subject: Test
---
 
::: columns {bg="#000000"}
::: col
Hello dark world
{color="secondary-text"}
:::
:::
.
color:#71717a

Section fusion — {flush}

Adjacent sections with {flush} are wrapped in <mj-wrapper>.

---
subject: Test
---
 
::: columns {bg="#f9f9f9" flush}
::: col
First section
:::
:::
 
::: columns {bg="#000000" flush}
::: col
Second section
:::
:::
.
<mj-wrapper
.
First section
.
Second section