
                                                              M. Schindler
Request for Comments: XXXX                                    March 2026
Category: Experimental


          Meltdown: A Declarative Profile Language for Semantic
            Interpretation of Markdown Documents

Status of This Memo

   This document describes an experimental declarative profile language
   for assigning semantic roles to plain Markdown documents and mapping
   those roles to backend-specific presentation layouts. Distribution
   of this memo is unlimited.

Abstract

   Markdown is widely used for authoring structured text. However,
   Markdown's structural primitives (headings, paragraphs, lists) do
   not express discourse function. Institutional document families
   such as legislative acts, parliamentary documents, and formal
   correspondence require layout decisions that depend on the semantic
   role of a text block, not merely its structural type.

   This document specifies Meltdown, a declarative profile language
   that infers discourse roles from unmodified Markdown source files
   and maps those roles to named presentation styles. A Meltdown
   profile is applied externally; the Markdown source requires no
   frontmatter, annotations, or embedded directives of any kind.

Table of Contents

   1.  Introduction  . . . . . . . . . . . . . . . . . . . . . . .  2
   2.  Terminology . . . . . . . . . . . . . . . . . . . . . . . .  3
   3.  Design Principles  . . . . . . . . . . . . . . . . . . . .  3
   4.  Input Model . . . . . . . . . . . . . . . . . . . . . . . .  4
   5.  Profile Structure . . . . . . . . . . . . . . . . . . . . .  5
   6.  Role Declaration  . . . . . . . . . . . . . . . . . . . . .  5
   7.  Recognition Rules . . . . . . . . . . . . . . . . . . . . .  6
   8.  Layout Mapping  . . . . . . . . . . . . . . . . . . . . . . 10
   9.  Presentation  . . . . . . . . . . . . . . . . . . . . . . . 10
   10. Processing Model  . . . . . . . . . . . . . . . . . . . . . 14
   11. Conformance . . . . . . . . . . . . . . . . . . . . . . . . 15
   12. Security Considerations . . . . . . . . . . . . . . . . . . 16
   13. IANA Considerations  . . . . . . . . . . . . . . . . . . . . 16
   Appendix A.  Complete Example Profile  . . . . . . . . . . . . . 17
   Appendix B.  Comparison with Related Work  . . . . . . . . . . . 20
   Author's Address  . . . . . . . . . . . . . . . . . . . . . . . 21

1.  Introduction

   Markdown [CommonMark] provides a lightweight syntax for expressing
   structural relationships between text blocks: headings, paragraphs,
   lists, blockquotes, tables, and code blocks. These structural
   primitives are sufficient for general-purpose authoring but do not
   capture discourse function.

   Consider a Markdown document representing a formal parliamentary
   inquiry. The first level-1 heading might identify the publisher.
   A level-2 heading might encode a document reference number and
   date. A level-3 heading might name the document type. These are
   discourse roles — semantic functions that depend on convention, not
   on heading level alone.

   Existing approaches to this problem typically require the author
   to annotate the source: YAML frontmatter, HTML class attributes,
   or custom delimiter syntax. These approaches violate the
   portability and simplicity that make Markdown attractive.

   Meltdown takes a different approach. A Meltdown profile is an
   external, declarative file that describes:

      (a) which semantic roles exist in a document family,
      (b) how to recognize those roles from the Markdown block
          stream, and
      (c) how to map recognized roles to presentation styles.

   The Markdown source is never modified. Different profiles can
   interpret the same source document for different institutional
   contexts.

1.1.  Scope

   This specification defines:

      - the syntax and semantics of Meltdown profile files,
      - the input model (Markdown block stream),
      - the recognition algorithm,
      - the layout mapping mechanism, and
      - the presentation primitives.

   This specification does NOT define:

      - a Markdown parser (any CommonMark-compliant parser is
        suitable),
      - a specific rendering backend (PDF, ODT, HTML, etc.), or
      - runtime APIs for engines.

2.  Terminology

   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.

   Block:
      A discrete structural unit in the Markdown document, as defined
      by the CommonMark specification. Examples: heading, paragraph,
      list, blockquote, table, code block.

   Block stream:
      The ordered sequence of Blocks resulting from parsing a Markdown
      document, preserving source order.

   Role:
      A semantic label assigned to a Block by the recognition engine.
      Roles are profile-specific and carry no inherent formatting.

   Profile:
      A Meltdown file (with the extension .meltdown) that declares
      roles, recognition rules, layout mappings, and presentation
      definitions for a document family.

   Engine:
      A conforming implementation that parses a profile, processes
      a block stream according to recognition rules, and produces
      a role-annotated document model.

   Renderer:
      A backend that takes the role-annotated document model and
      produces output in a concrete format (PDF, ODT, HTML, etc.).

   Style:
      A named set of typographic properties defined in the
      presentation section and referenced from the layout section.

3.  Design Principles

   The design of Meltdown is governed by three invariants.

3.1.  Separation of Concerns

   Meltdown enforces strict boundaries between three layers:

      +-------------------+-----------------------------------+
      | Layer             | Responsibility                    |
      +-------------------+-----------------------------------+
      | Markdown source   | Textual content                   |
      | Meltdown profile  | Semantic recognition and mapping  |
      | Renderer          | Typographic realization           |
      +-------------------+-----------------------------------+

   The Markdown source says WHAT is written. The Meltdown profile
   says what each part IS. The renderer says how each part LOOKS.

   A single Markdown document MAY be rendered into entirely different
   institutional layouts by applying different profiles.

3.2.  Declarative Constraint

   Meltdown profiles are purely declarative. The following constructs
   are prohibited:

      - procedural predicates,
      - loops or iteration,
      - user-defined functions,
      - runtime scripting or evaluation-order programming,
      - conditional logic beyond what is expressible through
        recognition predicates.

   Rationale: declarative profiles are deterministic, analyzable,
   portable, and diffable.

3.3.  Single-Pass Processing

   The recognition engine processes the block stream in exactly one
   pass, from first block to last. Once a block has been assigned a
   role, that assignment is final. There is no backtracking and no
   reclassification.

   This guarantees:

      - deterministic output for any given (source, profile) pair,
      - linear time complexity in the number of blocks, and
      - reproducibility across engine implementations.

4.  Input Model

   A Markdown document is parsed by a CommonMark-compliant parser
   into an ordered block stream. Meltdown operates on this block
   stream, not on the raw Markdown text.

4.1.  Block Types

   A conforming engine MUST support the following abstract block
   types:

      heading(level=n)    where n is an integer from 1 to 6
      paragraph
      list
      blockquote
      table
      codeblock

   An engine MAY define additional block types for extensions to
   CommonMark, but such types are outside the scope of this
   specification.

4.2.  Block Properties

   Each block in the stream carries at minimum:

      - its type (as listed in Section 4.1),
      - its text content (the concatenated inline text, with inline
        formatting stripped for predicate evaluation), and
      - its ordinal position in the stream (zero-indexed).

4.3.  Default Role

   Any block that is not matched by any recognition rule receives
   the implicit role "Body". Engines MUST NOT require explicit
   declaration of the "Body" role; it is always available.

5.  Profile Structure

5.1.  File Extension

   Meltdown profiles use the file extension:

      .meltdown

   No other extensions are defined by this specification.

5.2.  Encoding

   Profile files MUST be encoded in UTF-8.

5.3.  Syntax

   Profile files use YAML syntax as defined by the YAML 1.2
   specification.

5.4.  Profile Identity

   There is no mandatory profile header. The profile name is derived
   from the filename. For example, a file named "bt-drucksache.meltdown"
   has the profile name "bt-drucksache".

   The language version is implicitly the version supported by the
   engine processing the profile. There is no in-file version
   declaration.

5.5.  Top-Level Sections

   A profile file consists of up to three top-level sections, in the
   following canonical order:

      roles:       REQUIRED
      layout:      REQUIRED
      present:     OPTIONAL

   An engine MUST reject a profile that omits any REQUIRED section.
   An engine MUST accept a profile that omits any OPTIONAL section.
   Unknown top-level keys MUST cause an error in strict mode and
   SHOULD cause a warning in permissive mode.

6.  Roles

   The "roles" section defines the semantic vocabulary available
   for a document family and, for normal document-derived roles, how
   each role is recognized in the Markdown block stream.

6.1.  Syntax

      roles:
        <RoleName>:
               match:
                  - <block-type-predicate>
               where:                         # OPTIONAL
                  - <constraint>
               extract:                       # OPTIONAL
                  pattern: "<extraction-pattern>"
                  text: "<display-template>"  # OPTIONAL
               generated:                     # OPTIONAL alternative to match
                  from: <RoleName>
                  after: <RoleName>
               collect:                       # OPTIONAL transformation
                  as: <RoleName>
                  reference: previous
                  reference-format: "[{number}]"
                  insert-after: <RoleName>
                  fallback-heading: "<text>"
               description: "<text>"          # OPTIONAL
        <RoleName>:
        ...

    Each RoleName is a YAML key. Role names MUST match the regular
    expression [A-Za-z_][A-Za-z0-9_]* .

6.2.  Semantics

   Roles carry semantic meaning and recognition behavior, but no
   formatting information. A role declared in "roles" MAY be
   referenced in "layout" and "present".

   A role referenced in "layout" that is not declared in "roles"
   MUST cause an error.

   The "match" property is REQUIRED for normal document-derived
   roles. The "where", "extract", and "description" properties are
   OPTIONAL. A role MAY instead define "generated" to create a rendered
   block from another role or literal text without duplicating Markdown
   source content.

   A generated role MUST NOT define "match". A generated role MAY
   specify literal "text", a source role "from", an insertion point
   "before" or "after", and an output block "type". If "text" is
   present, that text is used as the block content. Otherwise, if
   "from" is present, the generated block copies content from the
   referenced source role. Generated blocks participate in layout and
   presentation like document-derived blocks, but they do not imply
   that the Markdown source contained the generated text.

   A normal document-derived role MAY define "collect". A collect
   declaration says that matched source blocks are not rendered in
   place. Instead, their content is gathered into a generated
   collection block, and a reference marker is attached to another
   block in the original flow. This is intended for document-family
   conventions such as footnotes, endnotes, citations, and explanatory
   notes. Collection is a Meltdown document-model transformation; it
   does not redefine Markdown code block semantics.

6.3.  Example

      roles:
        Herausgeber:
               match:
                  - heading(level=1)
               where:
                  - position == first
        DokumentMeta:
               match:
                  - heading(level=2)
               extract:
                  pattern: "Drucksache {Wahlperiode}/{Nummer} ({Datum})"
        Dokumentart:
               match:
                  - heading(level=3)
        Urheber:
               match:
                  - paragraph
        Titel:
               match:
                  - heading(level=2)
        Frageblock:
               match:
                  - paragraph
                  - list

7.  Recognition Rules

    The recognition fields inside each role define how the engine
    assigns roles to blocks in the Markdown block stream.

7.1.  General Structure

         roles:
            <RoleName>:
          match:
            - <block-type-predicate>
            - <block-type-predicate>    # additional accepted types
          where:
            - <constraint>
            - <constraint>
          extract:                       # OPTIONAL
            pattern: "<extraction-pattern>"
                  text: "<display-template>"   # OPTIONAL

        <RoleName>:
          ...

   Rules are evaluated in source order (the order in which they
   appear in the profile file). There are no priority numbers; the
   ordering of rules in the file IS the priority.

7.2.  Evaluation Algorithm

   For each block B in the block stream, the engine evaluates
   recognition rules in the order they appear in the profile:

      1. For each rule R (in profile order):
         a. If B's block type matches any entry in R's "match" list,
            AND
         b. If ALL constraints in R's "where" list (if present) are
            satisfied by B in its current context,
         THEN:
            - Assign the role specified by R to block B.
            - If R contains an "extract" clause, perform extraction
              (see Section 7.6).
            - Cease evaluating further rules for block B.

      2. If no rule matches block B, assign the role "Body".

   This is the First-Match-Wins principle. The first rule whose
   conditions are met wins, and the assignment is final.

7.3.  Match Predicates (Block Type)

   The "match" list specifies which block types a rule applies to.
   Multiple entries in the list are treated as a disjunction (OR):
   the block must match at least one entry.

   Supported match predicates:

      heading(level=<n>)     Matches a heading block at the
                             specified level (1-6).

      paragraph              Matches a paragraph block.

      list                   Matches a list block (ordered or
                             unordered).

      blockquote             Matches a blockquote block.

      table                  Matches a table block.

      codeblock              Matches a fenced or indented code
                             block.

      codeblock(info=<text>) Matches a fenced code block whose info
                    string begins with the given token. For
                    example, codeblock(info=citation)
                    matches ```citation and
                    ```citation smith-2026. The token after
                    "info=" MUST contain only ASCII letters,
                    digits, hyphen, and underscore.

   Example:

      match:
        - paragraph
        - list

   This matches blocks that are either paragraphs or lists.

7.4.  Where Constraints

   The "where" list specifies additional conditions that must ALL
   be true (conjunction / AND) for the rule to match. If "where"
   is omitted, the rule matches on block type alone.

7.4.1.  Positional Predicates

   position == first

      True if the block is the first block in the entire document
      that matches the "match" type constraint. This is a global
      position check, not role-local.

   follows <RoleName>

      True if the immediately preceding block (in the block stream)
      has been assigned the specified role. "Immediately preceding"
      means there are zero intervening blocks.

   after <RoleName>

      True if any block earlier in the stream has been assigned the
      specified role. Unlike "follows", intervening blocks of other
      roles may exist.

   before <RoleName>

      True if the specified role has NOT YET been assigned to any
      block in the stream at the point of evaluation. Because
      processing is single-pass, "before X" means "X has not been
      seen yet."

      Note: "before" is evaluated against the state of the engine
      at the moment the current block is being classified. It
      cannot look ahead; it can only assert that a role has not
      yet appeared.

7.4.2.  Text Predicates

   All text predicates operate on the block's text content with
   inline formatting markers removed.

   equals "<string>"

      True if the block's text content is exactly equal to the
      given string.

   startswith "<string>"

      True if the block's text content begins with the given
      string.

   contains "<string>"

      True if the block's text content contains the given string.

   Engines MAY support additional text predicates as extensions.
   Unknown predicates MUST cause an error.

7.4.3.  Block Shape Predicates

   multiline

      True if the block's raw textual content contains at least one
      line break. This predicate is useful for address blocks and
      similar conventional fields that are visually and semantically
      distinct because they occupy several lines.

7.5.  Multi-Match Rules

   A single rule MAY match multiple blocks in the same document.
   For example, a rule for "Frageblock" may match dozens of
   paragraphs. Each matched block independently receives the
   specified role.

   If a rule should match at most one block, the profile author
   SHOULD use "position == first", "follows", or other constraining
   predicates to limit the match.

7.6.  Variable Extraction

   A recognition rule MAY include an "extract" clause to derive
   named variables from the matched block's text content.

7.6.1.  Syntax

      extract:
        pattern: "<template-string>"
            text: "<display-template>"       # OPTIONAL

   The pattern template string contains literal text interspersed with
   named placeholders enclosed in curly braces: {Name}.

   The optional text template contains literal text and the same named
   placeholders. It defines the block content that renderers and
   exporters receive after recognition.

7.6.2.  Semantics

   The engine matches the template against the block's text content.
   Placeholders are bound from left to right, consuming the shortest
   text that permits the following literal segment to match. The final
   placeholder in a pattern consumes the remaining text.

   Each successfully bound placeholder produces a variable scoped
   to the role:

      <RoleName>.<PlaceholderName>

   For example, given the rule:

      DokumentMeta:
        match:
          - heading(level=2)
        extract:
          pattern: "Drucksache {Wahlperiode}/{Nummer} ({Datum})"

   and the block text "Drucksache 19/6966 (11.01.2019)", the engine
   produces:

      DokumentMeta.Wahlperiode = "19"
      DokumentMeta.Nummer      = "6966"
      DokumentMeta.Datum       = "11.01.2019"

   These variables are available for interpolation in the "present"
   section. If the rule also defines extract.text, the engine MUST
   replace the matched block's rendered text with that template after
   substituting extracted variables. This allows a profile to recognize
   ordinary Markdown such as "Date: June 10, 2025" while rendering the
   semantic value "June 10, 2025" without app-specific post-processing.
   section (see Section 9.3).

7.6.3.  Extraction Failure

   If the template does not match the block's text, the block is
   still assigned the role (the match and where conditions were
   satisfied), but no variables are produced. An engine SHOULD
   emit a diagnostic warning in this case.

7.7.  Rule Ordering Guidelines

   Because rule ordering determines evaluation priority, profile
   authors SHOULD order rules from most specific to least specific.
   Catch-all rules (e.g., matching all paragraphs after a certain
   point) SHOULD appear last.

   Example ordering rationale:

      - "SchlussortDatum" (startswith "Berlin, den") before
        "Frageblock" (all paragraphs after Einleitungsformel),
        because SchlussortDatum is more specific and must be
        checked first to avoid false capture by Frageblock.

7.8.  Collected Blocks

   Some document families use ordinary Markdown blocks as source
   material for generated apparatus elsewhere in the document. A
   Wikipedia-like article, for example, may use fenced code blocks
   with the info string "citation" to hold bibliographic source text:

      ```citation jaeger-2023
      Lars Jaeger. "Ada Lovelace (1815-1852): Inventor of Computer
      Algorithms". Springer International Publishing. 2023.
      ```

   Markdown defines this as a code block. Meltdown MAY assign that
   code block a semantic role and then collect it according to the
   profile. The Markdown source remains portable; the decision to
   group, number, suppress, and reference the block belongs to the
   Meltdown profile.

7.8.1.  Syntax

      roles:
        Citation:
          match:
            - codeblock(info=citation)
          collect:
            as: CitationList
            reference: previous
            reference-format: "[{number}]"
            insert-after: CitationsHeading
            fallback-heading: References

   The "as" field names the generated collection role. The role MAY
   be listed in "layout" and styled like any other role.

   The "reference" field defines where the inline reference marker is
   attached. This specification defines the value "previous", meaning
   the nearest preceding visible non-heading block in document order.
   Engines MAY define additional values in future versions.

   The "reference-format" field is a template for the inline marker.
   It receives the placeholder {number}, the 1-based number assigned
   to the collected item. The default is "[{number}]".

   The "insert-after" field names a role after which the generated
   collection block is inserted. If that role is not present and
   "fallback-heading" is provided, the engine generates a heading with
   the fallback text and appends the collection after it. If neither
   insertion point nor fallback heading can be resolved, the engine
   appends the collection at the end of the document.

7.8.2.  Semantics

   A collected source block MUST NOT be rendered in its original
   position. Its text content becomes one item in the generated
   collection block. Items are numbered in first occurrence order.

   For fenced code blocks, the first token of the info string selects
   the role through codeblock(info=...). Remaining info-string text MAY
   be used by engines as a collection key. If two collected blocks use
   the same non-empty key, an engine MAY merge them into one numbered
   item and attach multiple back-references to that item.

   The generated collection block has type "collection" or a more
   specific engine type such as "citationlist". Renderers SHOULD
   expose the item number, item text, and back-reference information to
   output formats that can represent links. Renderers that cannot
   represent links SHOULD still render the reference marker and the
   numbered collection text.

8.  Layout Mapping

   The "layout" section connects semantic roles to named styles.

8.1.  Syntax

      layout:
        <RoleName>:
          style: <StyleName>

   Each RoleName MUST correspond to a role declared in "roles" or
   assigned by a recognition rule. Each StyleName SHOULD correspond
   to a style defined in "present.styles" (Section 9.4).

8.2.  Semantics

   Layout mapping is a pure data association. It does not contain
   any formatting properties. The mapping tells the renderer: "for
   blocks with this role, apply this named style."

   Roles not listed in "layout" are rendered with the engine's
   default body style.

8.3.  Separation Invariant

   The "layout" section MUST NOT contain typographic properties
   (font-size, margin, alignment, etc.). All such properties belong
   in "present.styles". This separation ensures that roles (what
   something IS) remain independent from styles (how something
   LOOKS).

9.  Presentation

   The "present" section defines page geometry, master pages, and
   style definitions. This section is OPTIONAL. When omitted, the
   renderer applies its own defaults.

9.1.  Page Geometry

      present:
        page:
          size: <paper-size>
          orientation: portrait | landscape
          margins:
            top: <length>
            right: <length>
            bottom: <length>
            left: <length>

   Paper sizes: Engines MUST support "A4" and "Letter". Engines
   MAY support additional named sizes.

   Length values MUST include an explicit unit. Supported units:
   "mm", "cm", "pt", "in".

   Orientation MUST be either "portrait" or "landscape".

9.1.1.  Page Adornments

    A page MAY define named adornments. Adornments are presentation
    objects attached to the page rather than to a Markdown block.
    They are part of the Meltdown profile and MUST be available to all
    renderers through the document model.

         present:
            page:
               adornments:
                  <AdornmentName>:
                     type: rect | image
                     top: <length>
                     left: <length>        # OPTIONAL when right and width exist
                     right: <length>       # OPTIONAL when left and width exist
                     width: <length>       # OPTIONAL for rect with left/right
                     height: <length>
                     fill: <color>         # rect
                     background: <color>   # image container
                     border-radius: <length-or-percent>
                     image-size: <percent>
                     src: <relative-path>  # image
                     data: <inline-data>   # image

    A "rect" adornment draws a filled rectangle. A renderer MUST honor
    "fill" when the target format can represent solid fills.

    An "image" adornment draws an image in the specified box. The image
    MAY be referenced by "src" or embedded directly in "data". When
    both are present, "data" is authoritative and "src" is a fallback
    identifier for renderers or authoring tools that cannot consume
    inline data. Inline SVG data SHOULD be stored as a YAML quoted
    scalar or block scalar.

    Adornment coordinates are measured from the page edge, not from the
    body text frame. This distinction allows a profile to define visual
    marks such as letterhead bars, seals, or watermarks independently
    from body margins.

9.2.  Font Defaults

      present:
        fonts:
          body: "<font-family>"
          heading: "<font-family>"
          mono: "<font-family>"

   These are profile-level defaults. They MAY be overridden by
   individual style definitions in "present.styles".

9.3.  Master Pages

   Master pages define repeating content (headers and footers) that
   appears on every page of the rendered output.

9.3.1.  Syntax

      present:
        master:
          first-page:               # OPTIONAL
            header:
              left: "<content>"
              center: "<content>"
              right: "<content>"
            footer:
              left: "<content>"
              center: "<content>"
              right: "<content>"
          odd-page:
            header: ...
            footer: ...
          even-page:
            header: ...
            footer: ...

   Engines MUST support "odd-page" and "even-page". Engines SHOULD
   support "first-page". If "first-page" is not supported, the
   engine MUST fall back to "odd-page" for the first page.

   The positions "left", "center", and "right" are all OPTIONAL
   within a header or footer block.

9.3.2.  Content Interpolation

   Header and footer content strings support two forms of
   interpolation:

   Variable interpolation:

      {{<RoleName>.<VariableName>}}

   resolves to the value extracted by the corresponding recognition
   rule's "extract" clause (Section 7.6).

   Page variables:

      {{page.number}}    Current page number.
      {{page.count}}     Total page count.

   Engines MUST support variable interpolation and page variables
   in master page content.

9.3.3.  Inline Formatting

   Master page content strings MAY contain Markdown inline
   formatting (e.g., **bold**, *italic*). The renderer MUST
   interpret and render this formatting appropriately.

9.3.4.  Multi-Line Content

   Master page content MAY use YAML block scalars (literal "|" or
   folded ">") for multi-line content. The renderer MUST preserve
   line breaks in literal block scalars.

9.4.  Style Definitions

   The "present.styles" section defines the typographic properties
   of named styles referenced in the "layout" section.

9.4.1.  Syntax

      present:
        styles:
          <StyleName>:
            family: paragraph
            based-on: <ParentStyleName>    # OPTIONAL
            display: none                  # OPTIONAL
            position: static | relative | absolute
            top: <length>
            right: <length>
            bottom: <length>
            left: <length>
            width: <length>
            height: <length>
            min-height: <length>
            font-size: <length>
            font-weight: normal | bold
            font-style: normal | italic
            align: left | center | right | justify
            line-height: <number>
                  white-space: normal | pre-line | nowrap
                  text-transform: none | uppercase
            margin-top: <length>
            margin-bottom: <length>
            margin-left: <length>
            margin-right: <length>
            text-indent: <length>
               list-marker-width: <length>
               list-marker-gap: <length>
               list-marker-align: left | center | right
               list-nested-indent: <length>
               list-point-marker-width: <length>
               list-point-marker-gap: <length>
               list-point-marker-align: left | center | right
                  page-break-before: auto | always
                  first-line:                    # OPTIONAL nested style
                     font-size: <length>
                     font-weight: normal | bold
                     font-style: normal | italic
                        label:                         # OPTIONAL nested label
                           text: "<template-string>"
                           width: <length>
                           gap: <length>
                           align: left | center | right

   All properties within a style definition are OPTIONAL. Omitted
   properties inherit from the parent style (if "based-on" is
   specified) or from the engine's defaults.

    The "font-family" property names the preferred typeface stack for
    the style. The "font-size", "font-weight", and "font-style"
    properties describe text face selection. The "align" property
    controls paragraph alignment. The "line-height" property MAY be a
    unitless multiplier or a length.

    The "white-space" property controls preservation of line breaks in
    the block's source text. The value "pre-line" preserves line breaks
    while collapsing other whitespace. The value "nowrap" requests that
    renderers keep the block on one line when the target format permits
    it.

    The "text-transform" property applies a presentational case
    transform without modifying the Markdown source.

    The "page-break-before" property requests a page break before any
    block using the style. Renderers SHOULD honor "always" when the
    target format supports pagination.

   The "list-marker-width" and "list-marker-gap" properties request
   an explicit marker column for ordered list items. The marker text,
   such as "1.", occupies the marker column; the item body starts
   after the configured gap. This allows document families with fixed
   numbering columns to use normal Markdown ordered lists, including
   repeated "1." source markers. The "list-marker-align" property
   controls alignment within the marker column and defaults to left.
   Nested unordered list items MAY be rendered as legal point markers
   rather than bullet lists. Renderers MAY generate markers such as
   "(a)" for the first nested level and "(i)" for the second nested
   level. If the source text already begins with a parenthesized marker,
   such as "(a)" or "(i)", renderers SHOULD preserve that marker. The
   "list-nested-indent" property controls the additional indentation for
   deeper point levels, while "list-point-marker-width",
   "list-point-marker-gap", and "list-point-marker-align" control their
   marker column.

    The "first-line" nested style applies only to the first rendered
    line of a block. It is intended for document-family conventions such
    as sender-name treatments in letterhead addresses. A renderer that
    cannot reliably identify rendered line breaks MAY apply the nested
    style to the first source line instead.

   The "label" nested style defines a fixed-width label column before
   the block body. Its "text" field is a template evaluated against the
   matched block's extracted variables, using the same {Name}
   placeholders as extract.text. When applied to an ordered list, the
   template also receives {number}, the rendered ordinal of the current
   list item. The block body remains the block's rendered text, usually
   after extract.text has removed the label from the body. This
   primitive is intended for document-family conventions such as legal
   recitals, where labels like "(1)" occupy a separate column and all
   body lines align to the same text start. Renderers that cannot
   represent a label column SHOULD approximate it with a hanging indent.

9.4.2.  The "display: none" Property

   Setting "display: none" instructs the renderer to suppress the
   block's content in the document body. This is used when a block's
   text has been extracted into page headers or other layout elements
   via the "extract" mechanism and should not appear twice.

   The block is still recognized and its extracted variables remain
   available. Only its visual rendering in the body flow is
   suppressed.

9.4.3.  Style Name Constraints

   Style names MUST match the regular expression
   [A-Za-z_][A-Za-z0-9_]* .

   Style names in "layout" that do not correspond to any definition
   in "present.styles" SHOULD cause a warning. The renderer MAY
   fall back to backend-native styles with the same name.

10.  Processing Model

   This section describes the end-to-end processing of a Markdown
   document with a Meltdown profile.

10.1.  Phase 1: Profile Parsing

   The engine reads the .meltdown file and constructs an internal
   representation of:

      - the role vocabulary,
      - the ordered list of recognition rules,
      - the layout mapping, and
      - the presentation definitions (if present).

   The engine MUST validate that all role references in "recognize"
   and "layout" are declared in "roles". Unknown references MUST
   cause an error.

10.2.  Phase 2: Markdown Parsing

   The engine parses the Markdown source into a block stream using
   a CommonMark-compliant parser. The result is an ordered list of
   blocks, each annotated with its type and text content.

10.3.  Phase 3: Role Assignment

   The engine iterates over the block stream. For each block, it
   evaluates recognition rules in profile order until a match is
   found or all rules are exhausted (Section 7.2).

   After this phase, every block has exactly one assigned role
   (either a named role or the default "Body").

10.4.  Phase 4: Rendering

   Before rendering, the engine applies document-model transformations
   declared by roles, including generated blocks and collected blocks.
   These transformations operate on the role-annotated block stream
   and produce a renderable document model. They MUST be deterministic
   for a given Markdown source and profile.

   The renderer receives:

      - the block stream with assigned roles,
      - the layout mapping (role -> style name),
      - the extracted variables, and
      - the presentation definitions.

   The renderer materializes the output in its target format.
   The specifics of rendering are outside the scope of this
   specification.

11.  Conformance

11.1.  Engine Conformance

   A conforming Meltdown engine:

      - MUST parse all four profile sections (roles, recognize,
        layout, present).
      - MUST implement the First-Match-Wins evaluation algorithm
        as described in Section 7.2.
      - MUST support all match predicates listed in Section 7.3.
      - MUST support all where predicates listed in Section 7.4.
      - MUST support variable extraction as described in
        Section 7.6.
         - MUST support collected blocks as described in Section 7.8.
      - MUST assign "Body" to unmatched blocks.
      - MUST reject unknown predicates with an error.

11.2.  Strict and Permissive Modes

   Engines SHOULD support two operational modes:

   Strict mode:
      Unknown keys in any section cause an error. Unreferenced
      roles cause an error. Style names without definitions cause
      an error. This mode is RECOMMENDED for CI pipelines.

   Permissive mode:
      Unknown keys cause warnings. Unreferenced roles are ignored.
      Undefined style names fall back to renderer defaults. This
      mode is RECOMMENDED for interactive authoring.

12.  Security Considerations

   Meltdown profiles are declarative and do not permit execution of
   arbitrary code. However, implementers should consider the
   following:

12.1.  Template Injection

   Variable interpolation in master page content (Section 9.3.2)
   uses values extracted from the Markdown source. If the rendering
   backend interprets certain character sequences as directives
   (e.g., script injection in HTML backends), engines MUST sanitize
   or escape interpolated values appropriately for the target
   format.

12.2.  Resource Consumption

   While the single-pass algorithm guarantees linear time complexity,
   pathological profiles with large numbers of rules or deeply
   nested extraction patterns could consume significant memory.
   Engines SHOULD impose reasonable limits on profile complexity.

12.3.  File System Access

   Meltdown profiles may reference external resources such as image
   adornments. Such references MUST be subject to path validation to
   prevent path traversal attacks. Renderers SHOULD resolve relative
   references relative to the profile file, not the process working
   directory.

   Profiles may also contain embedded data, including inline SVG.
   Renderers MUST treat embedded image data as data, not executable
   code, and MUST sanitize or reject active content in formats that can
   contain scriptable resources.

12.4.  Raw Backend Escapes

   If a renderer provides a mechanism for embedding raw backend
   directives (e.g., raw LaTeX, raw HTML), this mechanism MUST be
   disabled by default and MUST require an explicit opt-in flag
   (e.g., --allow-raw-template).

13.  IANA Considerations

   This document requests no IANA actions.

   The file extension ".meltdown" is used by convention. No media
   type registration is proposed at this time.

   Should registration become desirable, an appropriate media type
   might be:

      application/vnd.meltdown+yaml

Appendix A.  Complete Example Profile

   The following profile demonstrates all features of the Meltdown
   language applied to a German parliamentary document
   (Bundestagsdrucksache, "Kleine Anfrage").

      # ================================================
      # Profile: bt-drucksache
      # Document family: German parliamentary inquiry
      # ================================================

      roles:
        Herausgeber:
          match:
            - heading(level=1)
          where:
            - position == first

        WahlperiodeZeile:
          match:
            - paragraph
                  - list
          where:
            - follows Herausgeber
          extract:
            pattern: "{Wahlperiode}. Wahlperiode"

        DokumentMeta:
          match:
            - heading(level=2)
          where:
            - follows Herausgeber
          extract:
            pattern: "Drucksache {Wahlperiode}/{Nummer} ({Datum})"

        Dokumentart:
          match:
            - heading(level=3)
          where:
            - equals "Kleine Anfrage"

        Urheber:
          match:
            - paragraph
          where:
            - follows Dokumentart

        Titel:
          match:
            - heading(level=2)
          where:
            - follows Urheber

        Einleitungstext:
          match:
            - paragraph
          where:
            - after Titel
            - before Einleitungsformel

        Einleitungsformel:
          match:
            - heading(level=2)
          where:
            - startswith "Wir fragen die Bundesregierung"

        SchlussortDatum:
          match:
            - paragraph
          where:
            - startswith "Berlin, den"

        SchlussSignatur:
          match:
            - paragraph
          where:
            - follows SchlussortDatum

        Frageblock:
          match:
            - paragraph
            - list
          where:
            - after Einleitungsformel

      layout:
        Herausgeber:
          style: BT_Verborgen
        WahlperiodeZeile:
          style: BT_Verborgen
        DokumentMeta:
          style: BT_Verborgen
        Dokumentart:
          style: BT_Dokumentart
        Urheber:
          style: BT_Urheber
        Titel:
          style: BT_Titel
        Einleitungstext:
          style: BT_Fliesstext
        Einleitungsformel:
          style: BT_Zwischenueberschrift
        Frageblock:
          style: BT_Fliesstext
        SchlussortDatum:
          style: BT_SchlussDatum
        SchlussSignatur:
          style: BT_Signatur

      present:
        page:
          size: A4
          orientation: portrait
          margins:
            top: 30mm
            right: 20mm
            bottom: 20mm
            left: 20mm

        master:
          first-page:
            header:
              left: >-
                **Deutscher Bundestag**
                {{DokumentMeta.Wahlperiode}}. Wahlperiode
              right: |
                **Drucksache**
                {{DokumentMeta.Wahlperiode}}/
                **{{DokumentMeta.Nummer}}**
                {{DokumentMeta.Datum}}

          odd-page:
            header:
              left: >-
                Deutscher Bundestag -
                {{DokumentMeta.Wahlperiode}}. Wahlperiode
              center: "{{page.number}}"
              right: >-
                Drucksache
                {{DokumentMeta.Wahlperiode}}/
                {{DokumentMeta.Nummer}}

          even-page:
            header:
              left: >-
                Drucksache
                {{DokumentMeta.Wahlperiode}}/
                {{DokumentMeta.Nummer}}
              center: "{{page.number}}"
              right: >-
                Deutscher Bundestag -
                {{DokumentMeta.Wahlperiode}}. Wahlperiode

        styles:
          BT_Verborgen:
            family: paragraph
            display: none

          BT_Dokumentart:
            family: paragraph
            font-size: 12pt
            font-weight: bold
            margin-top: 50mm

          BT_Urheber:
            family: paragraph
            font-size: 10pt
            line-height: 1.2
            margin-bottom: 10mm

          BT_Titel:
            family: paragraph
            font-size: 12pt
            font-weight: bold
            align: justify
            margin-bottom: 8mm

          BT_Zwischenueberschrift:
            family: paragraph
            font-size: 11pt
            margin-bottom: 4mm

          BT_Fliesstext:
            family: paragraph
            font-size: 10pt
            align: justify
            line-height: 1.15

          BT_SchlussDatum:
            family: paragraph
            font-size: 10pt
            margin-top: 8mm

          BT_Signatur:
            family: paragraph
            font-size: 10pt
            font-weight: bold

Appendix B.  Comparison with Related Work

B.1.  LaTeX

   LaTeX mixes content and formatting in the source file. A command
   like \section{Title} is both a structural declaration and a
   formatting instruction. Meltdown keeps these concerns strictly
   separated: the Markdown contains only text, and the profile
   describes interpretation and presentation externally.

B.2.  DSSSL

   The Document Style Semantics and Specification Language (DSSSL,
   ISO/IEC 10179:1996) is the closest historical ancestor to
   Meltdown's approach. DSSSL also separates recognition,
   transformation, and presentation of SGML documents. However,
   DSSSL is based on a Scheme-derived expression language,
   making it Turing-complete — the opposite of Meltdown's
   declarative constraint.

B.3.  XSLT / CSS

   XSLT transforms XML structure but requires XML input. CSS
   styles HTML elements by selector but does not perform semantic
   recognition — it assumes the author has already marked up the
   document with meaningful class names. Meltdown infers roles
   from unmodified Markdown, combining recognition and styling
   in a single profile.

B.4.  Pandoc Templates

   Pandoc's template system controls output formatting but relies
   on YAML frontmatter or Pandoc-specific syntax in the source
   document. Meltdown requires no source-side annotations.

Author's Address

   Mathias Schindler

   Email: mathiasschindler@github.com