<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <!-- ============================================================
       Simple Types
  ============================================================ -->

  <xs:simpleType name="TokenScale">
    <xs:restriction base="xs:string">
      <xs:enumeration value="xs"/>
      <xs:enumeration value="s"/>
      <xs:enumeration value="m"/>
      <xs:enumeration value="l"/>
      <xs:enumeration value="xl"/>
      <xs:enumeration value="xxl"/>
    </xs:restriction>
  </xs:simpleType>

  <!-- e.g. "10pt", "25.4mm", or "1in" (non-negative) -->
  <xs:simpleType name="PtValue">
    <xs:restriction base="xs:string">
      <xs:pattern value="\d+(\.\d+)?(pt|mm|in)"/>
    </xs:restriction>
  </xs:simpleType>

  <!-- Same as PtValue but allows a leading minus for coordinates and offsets -->
  <xs:simpleType name="SignedPtValue">
    <xs:restriction base="xs:string">
      <xs:pattern value="-?\d+(\.\d+)?(pt|mm|in)"/>
    </xs:restriction>
  </xs:simpleType>

  <!-- token name or explicit pt value, e.g. "m" or "14pt" -->
  <xs:simpleType name="TokenScaleOrPt">
    <xs:union memberTypes="TokenScale PtValue"/>
  </xs:simpleType>

  <!-- e.g. "10pt" | "10pt 12pt" | "10pt 12pt 8pt" | "10pt 12pt 8pt 6pt". A bare 0 needs no unit. -->
  <xs:simpleType name="SpacingValue">
    <xs:restriction base="xs:string">
      <xs:pattern value="(0|\d+(\.\d+)?pt)( (0|\d+(\.\d+)?pt)){0,3}"/>
    </xs:restriction>
  </xs:simpleType>

  <!-- spacing: explicit multi-pt shorthand OR a single token name -->
  <xs:simpleType name="SpacingOrToken">
    <xs:union memberTypes="SpacingValue TokenScale"/>
  </xs:simpleType>

  <xs:simpleType name="PageSizeNamed">
    <xs:restriction base="xs:string">
      <xs:enumeration value="a4"/>
      <xs:enumeration value="a3"/>
      <xs:enumeration value="a5"/>
      <xs:enumeration value="letter"/>
      <xs:enumeration value="legal"/>
    </xs:restriction>
  </xs:simpleType>

  <!-- e.g. "100pt 200pt" -->
  <xs:simpleType name="PageSizeCustom">
    <xs:restriction base="xs:string">
      <xs:pattern value="\d+(\.\d+)?pt \d+(\.\d+)?pt"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="PageSize">
    <xs:union memberTypes="PageSizeNamed PageSizeCustom"/>
  </xs:simpleType>

  <xs:simpleType name="Orientation">
    <xs:restriction base="xs:string">
      <xs:enumeration value="portrait"/>
      <xs:enumeration value="landscape"/>
    </xs:restriction>
  </xs:simpleType>

  <!-- e.g. "#1763cf" or "#fff" -->
  <xs:simpleType name="ColorHex">
    <xs:restriction base="xs:string">
      <xs:pattern value="#[0-9a-fA-F]{3}([0-9a-fA-F]{3})?"/>
    </xs:restriction>
  </xs:simpleType>

  <!-- hex or a named color token e.g. "primary", "surface-alt" -->
  <xs:simpleType name="Color">
    <xs:restriction base="xs:string">
      <xs:pattern value="#[0-9a-fA-F]{3}([0-9a-fA-F]{3})?|[a-z][a-z0-9-]*"/>
    </xs:restriction>
  </xs:simpleType>

  <!-- e.g. "s #ccc", "m primary", or "1.5pt #ccc" -->
  <xs:simpleType name="BorderValue">
    <xs:restriction base="xs:string">
      <xs:pattern value="(\d+(\.\d+)?pt|xs|s|m|l|xl|xxl) .+"/>
    </xs:restriction>
  </xs:simpleType>

  <!-- cross-axis alignment (stack cross-axis supports stretch) -->
  <xs:simpleType name="AlignFull">
    <xs:restriction base="xs:string">
      <xs:enumeration value="start"/>
      <xs:enumeration value="center"/>
      <xs:enumeration value="end"/>
      <xs:enumeration value="stretch"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="Align">
    <xs:restriction base="xs:string">
      <xs:enumeration value="start"/>
      <xs:enumeration value="center"/>
      <xs:enumeration value="end"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="Justify">
    <xs:restriction base="xs:string">
      <xs:enumeration value="start"/>
      <xs:enumeration value="center"/>
      <xs:enumeration value="end"/>
      <xs:enumeration value="between"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="Paginate">
    <xs:restriction base="xs:string">
      <xs:enumeration value="no"/>
      <xs:enumeration value="break-before"/>
      <xs:enumeration value="break-after"/>
      <xs:enumeration value="keep-next"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="TextAlignH">
    <xs:restriction base="xs:string">
      <xs:enumeration value="left"/>
      <xs:enumeration value="center"/>
      <xs:enumeration value="right"/>
      <xs:enumeration value="justify"/>
    </xs:restriction>
  </xs:simpleType>

  <!-- "full", "fill", or an explicit pt value e.g. "48pt" -->
  <xs:simpleType name="HeightValue">
    <xs:union memberTypes="HeightMode PtValue"/>
  </xs:simpleType>

  <xs:simpleType name="HeightMode">
    <xs:restriction base="xs:string">
      <xs:enumeration value="full"/>
      <xs:enumeration value="fill"/>
    </xs:restriction>
  </xs:simpleType>

  <!-- Nine reference points on the page (vertical-first naming) -->
  <xs:simpleType name="Anchor">
    <xs:restriction base="xs:string">
      <xs:enumeration value="top-left"/>
      <xs:enumeration value="top-center"/>
      <xs:enumeration value="top-right"/>
      <xs:enumeration value="center-left"/>
      <xs:enumeration value="center"/>
      <xs:enumeration value="center-right"/>
      <xs:enumeration value="bottom-left"/>
      <xs:enumeration value="bottom-center"/>
      <xs:enumeration value="bottom-right"/>
    </xs:restriction>
  </xs:simpleType>

  <!-- Keyword or numeric page range (section-relative) -->
  <xs:simpleType name="PageScope">
    <xs:union>
      <xs:simpleType>
        <xs:restriction base="xs:string">
          <xs:enumeration value="each"/>
          <xs:enumeration value="first"/>
          <xs:enumeration value="last"/>
          <xs:enumeration value="odd"/>
          <xs:enumeration value="even"/>
        </xs:restriction>
      </xs:simpleType>
      <xs:simpleType>
        <xs:restriction base="xs:string">
          <!-- matches: 1  |  1-3  |  1-last  |  1,3  |  1,3-5,7-last -->
          <xs:pattern value="[1-9]\d*(-([1-9]\d*|last))?(,[1-9]\d*(-([1-9]\d*|last))?)*"/>
        </xs:restriction>
      </xs:simpleType>
    </xs:union>
  </xs:simpleType>

  <xs:simpleType name="LineCap">
    <xs:restriction base="xs:string">
      <xs:enumeration value="butt"/>
      <xs:enumeration value="round"/>
      <xs:enumeration value="square"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="FillRule">
    <xs:restriction base="xs:string">
      <xs:enumeration value="nonzero"/>
      <xs:enumeration value="evenodd"/>
    </xs:restriction>
  </xs:simpleType>

  <!-- Pin positions for layout regions; top/bottom implemented in Phase 2;
       left/right schema-valid but implementation deferred. -->
  <xs:simpleType name="RegionPin">
    <xs:restriction base="xs:string">
      <xs:enumeration value="top"/>
      <xs:enumeration value="bottom"/>
      <xs:enumeration value="left"/>
      <xs:enumeration value="right"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="BuiltinFont">
    <xs:restriction base="xs:string">
      <xs:enumeration value="Courier"/>
      <xs:enumeration value="Courier-Bold"/>
      <xs:enumeration value="Courier-Oblique"/>
      <xs:enumeration value="Courier-BoldOblique"/>
      <xs:enumeration value="Helvetica"/>
      <xs:enumeration value="Helvetica-Bold"/>
      <xs:enumeration value="Helvetica-Oblique"/>
      <xs:enumeration value="Helvetica-BoldOblique"/>
      <xs:enumeration value="Times-Roman"/>
      <xs:enumeration value="Times-Bold"/>
      <xs:enumeration value="Times-Italic"/>
      <xs:enumeration value="Times-BoldItalic"/>
      <xs:enumeration value="Symbol"/>
      <xs:enumeration value="ZapfDingbats"/>
    </xs:restriction>
  </xs:simpleType>


  <!-- ============================================================
       Reusable complex types
  ============================================================ -->

  <!-- All six scale slots with pt values — used by every token row -->
  <xs:complexType name="TokenScaleRow">
    <xs:attribute name="xs"  type="PtValue" use="required"/>
    <xs:attribute name="s"   type="PtValue" use="required"/>
    <xs:attribute name="m"   type="PtValue" use="required"/>
    <xs:attribute name="l"   type="PtValue" use="required"/>
    <xs:attribute name="xl"  type="PtValue" use="required"/>
    <xs:attribute name="xxl" type="PtValue" use="required"/>
  </xs:complexType>


  <!-- ============================================================
       Shared attribute groups
  ============================================================ -->

  <!-- Data-binding attrs valid on any layout element.
       data-value  : dot-path to a scalar; replaces the element's text content.
       data-source : dot-path to an array; repeats this element once per item.
       data-if     : dot-path to a value; element is rendered only when truthy.
       data-if-not : dot-path to a value; element is rendered only when falsy. -->
  <xs:attributeGroup name="DataBindingAttrs">
    <xs:attribute name="data-value"  type="xs:string"/>
    <xs:attribute name="data-source" type="xs:string"/>
    <xs:attribute name="data-if"     type="xs:string"/>
    <xs:attribute name="data-if-not" type="xs:string"/>
  </xs:attributeGroup>

  <!-- Box attrs shared by all layout elements -->
  <xs:attributeGroup name="BoxAttrs">
    <xs:attribute name="font"       type="xs:string"/>
    <xs:attribute name="font-size"  type="TokenScaleOrPt"/>
    <xs:attribute name="gap"        type="TokenScaleOrPt"/>
    <xs:attribute name="padding"    type="SpacingOrToken">
      <xs:annotation>
        <xs:documentation>Space between the edge of the box and its content, written like CSS: one value for all sides, two for top-bottom and left-right, three for top, left-right and bottom, four for top, right, bottom and left.</xs:documentation>
      </xs:annotation>
    </xs:attribute>
    <xs:attribute name="height"     type="HeightValue">
      <xs:annotation>
        <xs:documentation>Height of the box. Leave it out to size to the content. A length fixes it; fill takes what is left after its siblings (shared equally if several use fill); full takes all the height available. Any of these stops the box splitting across pages.</xs:documentation>
      </xs:annotation>
    </xs:attribute>
    <xs:attribute name="background" type="Color"/>
    <xs:attribute name="border"     type="BorderValue"/>
    <xs:attribute name="radius"     type="TokenScaleOrPt"/>
    <xs:attribute name="paginate"   type="Paginate">
      <xs:annotation>
        <xs:documentation>Where the box falls in the page flow. no: never split the box, and move it whole to the next page when it does not fit. break-before: start it on a new page. break-after: start the next sibling on a new page. keep-next: keep it on one page with the sibling that follows, moving both to the next page if that sibling would not fit. break-before, break-after and keep-next take effect on the children of layout; on a box inside another box they are not applied. no applies at any depth.</xs:documentation>
      </xs:annotation>
    </xs:attribute>
    <xs:attribute name="debug"      type="xs:boolean"/>
    <xs:attributeGroup ref="DataBindingAttrs"/>
  </xs:attributeGroup>

  <!-- Box attrs for frame — no gap (frame always centers its single child) -->
  <xs:attributeGroup name="FrameBoxAttrs">
    <xs:attribute name="font"       type="xs:string"/>
    <xs:attribute name="font-size"  type="TokenScaleOrPt"/>
    <xs:attribute name="padding"    type="SpacingOrToken">
      <xs:annotation>
        <xs:documentation>Space between the edge of the box and its content, written like CSS: one value for all sides, two for top-bottom and left-right, three for top, left-right and bottom, four for top, right, bottom and left.</xs:documentation>
      </xs:annotation>
    </xs:attribute>
    <xs:attribute name="height"     type="HeightValue">
      <xs:annotation>
        <xs:documentation>Height of the box. Leave it out to size to the content. A length fixes it; fill takes what is left after its siblings (shared equally if several use fill); full takes all the height available. Any of these stops the box splitting across pages.</xs:documentation>
      </xs:annotation>
    </xs:attribute>
    <xs:attribute name="background" type="Color"/>
    <xs:attribute name="border"     type="BorderValue"/>
    <xs:attribute name="radius"     type="TokenScaleOrPt"/>
    <xs:attribute name="paginate"   type="Paginate">
      <xs:annotation>
        <xs:documentation>Where the box falls in the page flow. no: never split the box, and move it whole to the next page when it does not fit. break-before: start it on a new page. break-after: start the next sibling on a new page. keep-next: keep it on one page with the sibling that follows, moving both to the next page if that sibling would not fit. break-before, break-after and keep-next take effect on the children of layout; on a box inside another box they are not applied. no applies at any depth.</xs:documentation>
      </xs:annotation>
    </xs:attribute>
    <xs:attribute name="debug"      type="xs:boolean"/>
    <xs:attributeGroup ref="DataBindingAttrs"/>
  </xs:attributeGroup>

  <!-- ============================================================
       Canvas primitives — named group of flat drawing elements.
       <layer> is not in this group; nesting is not permitted.
  ============================================================ -->

  <!-- Shared fill/stroke attributes for canvas primitives -->
  <xs:attributeGroup name="CanvasFillStrokeAttrs">
    <xs:attribute name="fill"         type="Color"/>
    <xs:attribute name="stroke"       type="Color"/>
    <xs:attribute name="stroke-width" type="PtValue"/>
    <xs:attribute name="stroke-dash"  type="xs:string"/>
    <xs:attribute name="opacity">
      <xs:simpleType>
        <xs:restriction base="xs:decimal">
          <xs:minInclusive value="0"/>
          <xs:maxInclusive value="1"/>
        </xs:restriction>
      </xs:simpleType>
    </xs:attribute>
  </xs:attributeGroup>

  <!-- Positioning rule (enforced by parser, not XSD 1.0):
       anchor OR (x AND y) must be present.
       When anchor is present, x/y are signed offsets from that reference point. -->
  <xs:group name="CanvasPrimitives">
    <xs:choice>

      <!-- rect -->
      <xs:element name="rect">
        <xs:complexType>
          <xs:attribute name="x"      type="SignedPtValue"/>
          <xs:attribute name="y"      type="SignedPtValue"/>
          <xs:attribute name="w"      type="PtValue" use="required"/>
          <xs:attribute name="h"      type="PtValue" use="required"/>
          <xs:attribute name="anchor" type="Anchor"/>
          <xs:attribute name="radius" type="PtValue"/>
          <xs:attributeGroup ref="CanvasFillStrokeAttrs"/>
        </xs:complexType>
      </xs:element>

      <!-- circle -->
      <xs:element name="circle">
        <xs:complexType>
          <xs:attribute name="cx"     type="SignedPtValue"/>
          <xs:attribute name="cy"     type="SignedPtValue"/>
          <xs:attribute name="r"      type="PtValue" use="required"/>
          <xs:attribute name="anchor" type="Anchor"/>
          <xs:attributeGroup ref="CanvasFillStrokeAttrs"/>
        </xs:complexType>
      </xs:element>

      <!-- ellipse -->
      <xs:element name="ellipse">
        <xs:complexType>
          <xs:attribute name="cx"     type="SignedPtValue"/>
          <xs:attribute name="cy"     type="SignedPtValue"/>
          <xs:attribute name="rx"     type="PtValue" use="required"/>
          <xs:attribute name="ry"     type="PtValue" use="required"/>
          <xs:attribute name="anchor" type="Anchor"/>
          <xs:attributeGroup ref="CanvasFillStrokeAttrs"/>
        </xs:complexType>
      </xs:element>

      <!-- line (no anchor — x1/y1/x2/y2 always required) -->
      <xs:element name="line">
        <xs:complexType>
          <xs:attribute name="x1"          type="SignedPtValue" use="required"/>
          <xs:attribute name="y1"          type="SignedPtValue" use="required"/>
          <xs:attribute name="x2"          type="SignedPtValue" use="required"/>
          <xs:attribute name="y2"          type="SignedPtValue" use="required"/>
          <xs:attribute name="stroke"       type="Color"/>
          <xs:attribute name="stroke-width" type="PtValue"/>
          <xs:attribute name="stroke-dash"  type="xs:string"/>
          <xs:attribute name="line-cap"     type="LineCap"/>
        </xs:complexType>
      </xs:element>

      <!-- path (no anchor — SVG-compatible d attribute) -->
      <xs:element name="path">
        <xs:complexType>
          <xs:attribute name="d"            type="xs:string" use="required"/>
          <xs:attribute name="fill"         type="Color"/>
          <xs:attribute name="stroke"       type="Color"/>
          <xs:attribute name="fill-rule"    type="FillRule"/>
          <xs:attribute name="stroke-width" type="PtValue"/>
          <xs:attribute name="stroke-dash"  type="xs:string"/>
          <xs:attribute name="line-cap"     type="LineCap"/>
          <xs:attribute name="opacity">
            <xs:simpleType>
              <xs:restriction base="xs:decimal">
                <xs:minInclusive value="0"/>
                <xs:maxInclusive value="1"/>
              </xs:restriction>
            </xs:simpleType>
          </xs:attribute>
        </xs:complexType>
      </xs:element>

      <!-- text — absolutely positioned; <span> children for mixed runs -->
      <xs:element name="text">
        <xs:annotation>
          <xs:documentation>Text at an exact position on the page: either x and y, or an anchor with optional offsets.</xs:documentation>
        </xs:annotation>
        <xs:complexType mixed="true">
          <xs:choice minOccurs="0" maxOccurs="unbounded">
            <xs:element ref="span"/>
          </xs:choice>
          <xs:attribute name="x"           type="SignedPtValue"/>
          <xs:attribute name="y"           type="SignedPtValue"/>
          <xs:attribute name="anchor"      type="Anchor"/>
          <xs:attribute name="font"        type="xs:string"/>
          <xs:attribute name="font-size"   type="TokenScaleOrPt"/>
          <xs:attribute name="color"       type="Color"/>
          <xs:attribute name="align"       type="TextAlignH"/>
          <xs:attribute name="w"           type="PtValue"/>
          <xs:attribute name="line-height">
            <xs:simpleType>
              <xs:restriction base="xs:decimal">
                <xs:minInclusive value="0"/>
              </xs:restriction>
            </xs:simpleType>
          </xs:attribute>
          <xs:attribute name="opacity">
            <xs:simpleType>
              <xs:restriction base="xs:decimal">
                <xs:minInclusive value="0"/>
                <xs:maxInclusive value="1"/>
              </xs:restriction>
            </xs:simpleType>
          </xs:attribute>
          <xs:attributeGroup ref="DataBindingAttrs"/>
        </xs:complexType>
      </xs:element>

      <!-- img — absolutely positioned; w and h required (no auto-sizing) -->
      <xs:element name="img">
        <xs:complexType>
          <xs:attribute name="name"   type="xs:string" use="required"/>
          <xs:attribute name="x"      type="SignedPtValue"/>
          <xs:attribute name="y"      type="SignedPtValue"/>
          <xs:attribute name="w"      type="PtValue" use="required"/>
          <xs:attribute name="h"      type="PtValue" use="required"/>
          <xs:attribute name="anchor" type="Anchor"/>
          <xs:attributeGroup ref="DataBindingAttrs"/>
        </xs:complexType>
      </xs:element>

    </xs:choice>
  </xs:group>

  <!-- Canvas wrapper: contains absolute-coordinate content.
       Coordinates are top-left origin, y-down, relative to the full page.
       Page targeting is via <layer page="…">; bare primitives are not permitted. -->
  <xs:element name="canvas">
    <xs:annotation>
      <xs:documentation>Draws at exact positions on the page, independent of the flowing layout: watermarks, stamps, page furniture. Coordinates start at the top left corner of the whole page, not the margin, and y grows downward. Shapes must sit inside a layer.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
      <xs:sequence>
        <!-- layer: graphics state scope (page, opacity, transform, clip).
             All primitives must be inside a <layer>. Cannot nest. -->
        <xs:element name="layer" minOccurs="0" maxOccurs="unbounded">
          <xs:annotation>
            <xs:documentation>Groups canvas shapes and sets what applies to all of them: which pages they appear on, opacity, transform and clip. Layers cannot be nested.</xs:documentation>
          </xs:annotation>
          <xs:complexType>
            <xs:sequence>
              <xs:group ref="CanvasPrimitives" minOccurs="0" maxOccurs="unbounded"/>
            </xs:sequence>
            <xs:attribute name="page"      type="PageScope"/>
            <xs:attribute name="opacity">
              <xs:simpleType>
                <xs:restriction base="xs:decimal">
                  <xs:minInclusive value="0"/>
                  <xs:maxInclusive value="1"/>
                </xs:restriction>
              </xs:simpleType>
            </xs:attribute>
            <xs:attribute name="transform" type="xs:string"/>
            <xs:attribute name="clip"      type="xs:string"/>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>


  <!-- ============================================================
       Layout content group — any layout element can nest any other
  ============================================================ -->

  <xs:group name="LayoutContent">
    <xs:choice>
      <xs:element ref="stack"/>
      <xs:element ref="flank"/>
      <xs:element ref="split"/>
      <xs:element ref="cluster"/>
      <xs:element ref="grid"/>
      <xs:element ref="frame"/>
      <xs:element ref="link"/>
      <xs:element ref="text"/>
      <xs:element ref="img"/>
      <xs:element ref="divider"/>
      <xs:element ref="table"/>
      <xs:element ref="barcode"/>
      <xs:element ref="field"/>
    </xs:choice>
  </xs:group>


  <!-- ============================================================
       Token elements
  ============================================================ -->

  <!-- Font asset: either a built-in PDF core font (core=) or a registry key (ref=) -->
  <xs:element name="font">
    <xs:annotation>
        <xs:documentation>Declares a font that text can be set in by name, with the font attribute. A built-in PDF font is named by core; any other font is a file the SDK reads from src, or one loaded on the engine under ref or, with no ref, under the font's own name.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    <xs:attribute name="name" type="xs:string" use="required">
      <xs:annotation>
        <xs:documentation>The name that the font attribute of a text uses to pick this font: lowercase letters, digits and -, starting with a letter.</xs:documentation>
      </xs:annotation>
    </xs:attribute>
    <xs:attribute name="core" type="BuiltinFont">
      <xs:annotation>
        <xs:documentation>A built-in PDF font, which needs no file.</xs:documentation>
      </xs:annotation>
    </xs:attribute>
    <xs:attribute name="ref" type="xs:string">
      <xs:annotation>
        <xs:documentation>The key the font was loaded under on the engine, when that is not its name.</xs:documentation>
      </xs:annotation>
    </xs:attribute>
    <xs:attribute name="src" type="xs:anyURI">
      <xs:annotation>
        <xs:documentation>A path the SDK reads the font file from, when the font was not loaded on the engine.</xs:documentation>
      </xs:annotation>
    </xs:attribute>
    </xs:complexType>
  </xs:element>

  <!-- Image asset declared in <assets> -->
  <xs:element name="image">
    <xs:annotation>
        <xs:documentation>Declares an image that an img refers to by name. The SDK reads the file from src, or the image was loaded on the engine under ref or, with no ref, under its own name.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    <xs:attribute name="name" type="xs:string" use="required">
      <xs:annotation>
        <xs:documentation>The name that the name attribute of an img uses to pick this image: lowercase letters, digits and -, starting with a letter.</xs:documentation>
      </xs:annotation>
    </xs:attribute>
    <xs:attribute name="ref" type="xs:string">
      <xs:annotation>
        <xs:documentation>The key the image was loaded under on the engine, when that is not its name.</xs:documentation>
      </xs:annotation>
    </xs:attribute>
    <xs:attribute name="src" type="xs:anyURI">
      <xs:annotation>
        <xs:documentation>A path the SDK reads the image file from, when the image was not loaded on the engine.</xs:documentation>
      </xs:annotation>
    </xs:attribute>
    </xs:complexType>
  </xs:element>

  <xs:element name="color">
    <xs:complexType>
      <xs:attribute name="name"  type="xs:string" use="required"/>
      <xs:attribute name="value" type="ColorHex"  use="required"/>
    </xs:complexType>
  </xs:element>

  <xs:element name="tokens">
    <xs:complexType>
      <xs:all>
        <xs:element name="space"  type="TokenScaleRow" minOccurs="0"/>
        <xs:element name="border" type="TokenScaleRow" minOccurs="0"/>
        <xs:element name="radius" type="TokenScaleRow" minOccurs="0"/>
        <xs:element name="width"  type="TokenScaleRow" minOccurs="0"/>
        <xs:element name="text-size" type="TokenScaleRow" minOccurs="0"/>
        <!-- "grid" and "space" share the same shape -->
        <xs:element name="grid"   type="TokenScaleRow" minOccurs="0"/>
        <xs:element name="colors" minOccurs="0">
          <xs:complexType>
            <xs:sequence>
              <xs:element ref="color" minOccurs="0" maxOccurs="unbounded"/>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:all>
    </xs:complexType>
  </xs:element>

  <!-- Asset declarations: fonts and images used by layout elements -->
  <xs:element name="assets">
    <xs:complexType>
      <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:element ref="font"/>
        <xs:element ref="image"/>
      </xs:choice>
    </xs:complexType>
  </xs:element>


  <!-- ============================================================
       Document structure
  ============================================================ -->

  <xs:element name="meta">
    <xs:complexType>
      <xs:attribute name="title"    type="xs:string"/>
      <xs:attribute name="author"   type="xs:string"/>
      <xs:attribute name="subject"  type="xs:string"/>
      <xs:attribute name="keywords" type="xs:string"/>
      <xs:attribute name="creator"  type="xs:string"/>
    </xs:complexType>
  </xs:element>

  <xs:element name="layout">
    <xs:annotation>
      <xs:documentation>The flowing content of a section. Elements stack down the page, and a new page starts when one runs out of room. Put headers and footers in a region, which sits outside the flow.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
      <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:group ref="LayoutContent"/>
        <!-- Pinned region: reserves a slot at the specified edge of the content area.
             pin="top|bottom" implemented in this phase.
             pin="left|right" schema-valid but deferred (requires w attribute).
             Only valid as a direct child of <layout>, not inside containers.
             At most one region per pin per physical page (parser-enforced). -->
        <xs:element name="region">
          <xs:annotation>
            <xs:documentation>Pins content to the top or bottom edge of pages, outside the normal flow, for headers and footers. It reserves that space on every page it appears on. Only allowed directly inside layout, and one per pin on a page.</xs:documentation>
          </xs:annotation>
          <xs:complexType>
            <xs:sequence>
              <xs:group ref="LayoutContent" minOccurs="0" maxOccurs="unbounded"/>
            </xs:sequence>
            <xs:attribute name="pin"   type="RegionPin" use="required">
              <xs:annotation>
                <xs:documentation>Which edge the region sticks to. top and bottom work. left and right pass validation but are not implemented yet.</xs:documentation>
              </xs:annotation>
            </xs:attribute>
            <xs:attribute name="page"  type="PageScope">
              <xs:annotation>
                <xs:documentation>Which pages show the region: each, first, last, odd, even, or a range such as 2-last. Defaults to each.</xs:documentation>
              </xs:annotation>
            </xs:attribute>
            <!-- w required for pin="left|right"; ignored for pin="top|bottom" (parser-enforced) -->
            <xs:attribute name="w"     type="PtValue"/>
            <xs:attribute name="debug" type="xs:boolean"/>
          </xs:complexType>
        </xs:element>
      </xs:choice>
    </xs:complexType>
  </xs:element>

  <!-- document: holds default page settings; contains one or more sections.
       layout and canvas go inside a section, never directly in document: the engine
       stops with "unexpected element in <document>". -->
  <xs:element name="document">
    <xs:annotation>
      <xs:documentation>The whole document, and the page settings every section starts from: size, orientation, margin and font. It holds an optional meta element and at least one section.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="meta" minOccurs="0"/>
        <xs:element ref="section" maxOccurs="unbounded"/>
      </xs:sequence>
      <xs:attribute name="font"        type="xs:string"/>
      <xs:attribute name="size"        type="PageSize"/>
      <xs:attribute name="orientation" type="Orientation"/>
      <xs:attribute name="margin"      type="SpacingValue"/>
      <xs:attribute name="background"  type="Color"/>
      <xs:attribute name="debug"       type="xs:boolean"/>
    </xs:complexType>
  </xs:element>

  <!-- section: a content boundary with its own auto-pagination.
       Attributes override document-level defaults for this section only.
       title is read but not yet written to the PDF: there is no outline.
       Four valid content combinations; document order = paint order. -->
  <xs:element name="section">
    <xs:annotation>
      <xs:documentation>A run of pages with its own settings, which override the document's. Each section paginates on its own. Its title is accepted but not yet used: the PDF has no bookmarks.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
      <xs:choice minOccurs="0">
        <!-- layout only, or layout + canvas overlay (layout painted first) -->
        <xs:sequence>
          <xs:element ref="layout"/>
          <xs:element ref="canvas" minOccurs="0"/>
        </xs:sequence>
        <!-- canvas only, or canvas underlay + layout (canvas painted first) -->
        <xs:sequence>
          <xs:element ref="canvas"/>
          <xs:element ref="layout" minOccurs="0"/>
        </xs:sequence>
      </xs:choice>
      <xs:attribute name="size"        type="PageSize"/>
      <xs:attribute name="orientation" type="Orientation"/>
      <xs:attribute name="margin"      type="SpacingValue"/>
      <xs:attribute name="background"  type="Color"/>
      <xs:attribute name="title"       type="xs:string"/>
      <xs:attribute name="debug"       type="xs:boolean"/>
    </xs:complexType>
  </xs:element>

  <!-- Root element -->
  <xs:element name="lpdf">
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="assets"   minOccurs="0"/>
        <xs:element ref="tokens"   minOccurs="0"/>
        <xs:element ref="document"/>
      </xs:sequence>
      <xs:attribute name="version" type="xs:positiveInteger" use="required"/>
    </xs:complexType>
  </xs:element>


  <!-- ============================================================
       Layout elements
  ============================================================ -->

  <xs:element name="stack">
    <xs:annotation>
      <xs:documentation>Places children top to bottom, each at the full width, with gap between them. Can split across pages between children.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
      <xs:sequence>
        <xs:group ref="LayoutContent" minOccurs="0" maxOccurs="unbounded"/>
      </xs:sequence>
      <xs:attributeGroup ref="BoxAttrs"/>
      <xs:attribute name="align"   type="AlignFull"/>
      <xs:attribute name="justify" type="Justify"/>
      <xs:attribute name="width"   type="TokenScaleOrPt"/>
    </xs:complexType>
  </xs:element>

  <xs:element name="flank">
    <xs:annotation>
      <xs:documentation>One row where the children keep their own width except one, which fills the rest. By default the last child fills; set end to true and the first fills. Never splits across pages.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
      <xs:sequence>
        <xs:group ref="LayoutContent" minOccurs="0" maxOccurs="unbounded"/>
      </xs:sequence>
      <xs:attributeGroup ref="BoxAttrs"/>
      <xs:attribute name="align" type="Align"/>
      <xs:attribute name="end"   type="xs:boolean">
        <xs:annotation>
          <xs:documentation>false (the default): every child but the last keeps its own width at the left, and the last fills the rest. true: the first child fills, and the others keep their own width at the right.</xs:documentation>
        </xs:annotation>
      </xs:attribute>
      <xs:attribute name="width" type="TokenScaleOrPt"/>
    </xs:complexType>
  </xs:element>

  <xs:element name="split">
    <xs:annotation>
      <xs:documentation>Two children side by side; any further children are ignored. By default each keeps its own width, the first at the left edge and the second at the right. With equal set to true they take half the width each. Never splits across pages.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
      <xs:sequence>
        <xs:group ref="LayoutContent" minOccurs="0" maxOccurs="unbounded"/>
      </xs:sequence>
      <xs:attributeGroup ref="BoxAttrs"/>
      <xs:attribute name="align" type="Align"/>
      <xs:attribute name="equal" type="xs:boolean">
        <xs:annotation>
          <xs:documentation>false (the default): each child keeps its own width, the first at the left edge and the second at the right edge. true: the two children share the width in equal halves.</xs:documentation>
        </xs:annotation>
      </xs:attribute>
      <xs:attribute name="width" type="TokenScaleOrPt"/>
    </xs:complexType>
  </xs:element>

  <xs:element name="cluster">
    <xs:annotation>
      <xs:documentation>A row that wraps: children sit side by side, and continue on the next line when they run out of width. Splits across pages between lines.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
      <xs:sequence>
        <xs:group ref="LayoutContent" minOccurs="0" maxOccurs="unbounded"/>
      </xs:sequence>
      <xs:attributeGroup ref="BoxAttrs"/>
      <xs:attribute name="align"   type="AlignFull"/>
      <xs:attribute name="justify" type="Justify"/>
      <xs:attribute name="width"   type="TokenScaleOrPt"/>
    </xs:complexType>
  </xs:element>

  <xs:element name="grid">
    <xs:annotation>
      <xs:documentation>Fills a fixed number of equal columns from left to right, then starts a new row. A row never splits across pages. For data with a header row, use table.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
      <xs:sequence>
        <xs:group ref="LayoutContent" minOccurs="0" maxOccurs="unbounded"/>
      </xs:sequence>
      <xs:attributeGroup ref="BoxAttrs"/>
      <xs:attribute name="width" type="TokenScaleOrPt"/>
      <xs:attribute name="col-width" type="TokenScaleOrPt"/>
      <xs:attribute name="cols">
        <xs:simpleType>
          <xs:restriction base="xs:positiveInteger">
            <xs:minInclusive value="1"/>
            <xs:maxInclusive value="12"/>
          </xs:restriction>
        </xs:simpleType>
      </xs:attribute>
    </xs:complexType>
  </xs:element>

  <xs:element name="frame">
    <xs:annotation>
      <xs:documentation>A box around a single child, which it centres. Never splits across pages: if it does not fit, the whole box moves to the next page.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
      <xs:sequence>
        <xs:group ref="LayoutContent" minOccurs="0" maxOccurs="1"/>
      </xs:sequence>
      <xs:attributeGroup ref="FrameBoxAttrs"/>
      <xs:attribute name="width" type="TokenScaleOrPt"/>
    </xs:complexType>
  </xs:element>

  <xs:element name="link">
    <xs:complexType>
      <xs:sequence>
        <xs:group ref="LayoutContent" minOccurs="0" maxOccurs="unbounded"/>
      </xs:sequence>
      <xs:attribute name="href"   type="xs:anyURI" use="required"/>
      <xs:attribute name="gap"    type="SpacingOrToken"/>
      <xs:attribute name="width"  type="TokenScaleOrPt"/>
      <xs:attribute name="height" type="HeightValue"/>
      <xs:attribute name="debug"  type="xs:boolean"/>
      <xs:attributeGroup ref="DataBindingAttrs"/>
    </xs:complexType>
  </xs:element>

  <xs:element name="divider">
    <xs:complexType>
      <xs:attribute name="direction">
        <xs:simpleType>
          <xs:restriction base="xs:string">
            <xs:enumeration value="horizontal"/>
            <xs:enumeration value="vertical"/>
          </xs:restriction>
        </xs:simpleType>
      </xs:attribute>
      <xs:attribute name="color"     type="Color"/>
      <xs:attribute name="thickness" type="TokenScaleOrPt"/>
      <xs:attribute name="debug"     type="xs:boolean"/>
      <xs:attributeGroup ref="DataBindingAttrs"/>
    </xs:complexType>
  </xs:element>

  <xs:element name="span">
    <xs:complexType mixed="true">
      <xs:attribute name="font"      type="xs:string"/>
      <xs:attribute name="bold"      type="xs:boolean"/>
      <xs:attribute name="color"     type="Color"/>
      <xs:attribute name="href"      type="xs:anyURI"/>
      <xs:attribute name="underline" type="xs:boolean"/>
      <xs:attribute name="strike"    type="xs:boolean"/>
    </xs:complexType>
  </xs:element>

  <xs:element name="img">
    <xs:complexType>
      <!-- <img> uses a pt-only height constraint, not HeightMode (fill/full) -->
      <xs:attribute name="name"       type="xs:string"     use="required"/>
      <xs:attribute name="height"     type="PtValue"/>
      <xs:attribute name="width"      type="TokenScaleOrPt"/>
      <xs:attribute name="font"       type="xs:string"/>
      <xs:attribute name="font-size"  type="TokenScaleOrPt"/>
      <xs:attribute name="gap"        type="TokenScaleOrPt"/>
      <xs:attribute name="padding"    type="SpacingOrToken"/>
      <xs:attribute name="background" type="Color"/>
      <xs:attribute name="border"     type="BorderValue"/>
      <xs:attribute name="radius"     type="TokenScaleOrPt"/>
      <xs:attribute name="paginate"   type="Paginate"/>
      <xs:attribute name="debug"      type="xs:boolean"/>
      <xs:attributeGroup ref="DataBindingAttrs"/>
    </xs:complexType>
  </xs:element>

  <xs:element name="barcode">
    <xs:complexType>
      <xs:attribute name="type" use="required">
        <xs:simpleType>
          <xs:restriction base="xs:string">
            <xs:enumeration value="qr"/>
            <xs:enumeration value="code128"/>
            <xs:enumeration value="ean13"/>
          </xs:restriction>
        </xs:simpleType>
      </xs:attribute>
      <xs:attribute name="data"       type="xs:string"       use="required"/>
      <xs:attribute name="size"       type="TokenScaleOrPt"/>
      <xs:attribute name="width"      type="TokenScaleOrPt"/>
      <xs:attribute name="height"     type="PtValue"/>
      <xs:attribute name="ec">
        <xs:simpleType>
          <xs:restriction base="xs:string">
            <xs:enumeration value="L"/>
            <xs:enumeration value="M"/>
            <xs:enumeration value="Q"/>
            <xs:enumeration value="H"/>
          </xs:restriction>
        </xs:simpleType>
      </xs:attribute>
      <xs:attribute name="hrt"        type="xs:boolean"/>
      <xs:attribute name="color"      type="Color"/>
      <xs:attribute name="background" type="Color"/>
      <xs:attribute name="paginate"   type="Paginate"/>
      <xs:attribute name="debug"      type="xs:boolean"/>
      <xs:attributeGroup ref="DataBindingAttrs"/>
    </xs:complexType>
  </xs:element>

  <xs:element name="text">
    <xs:annotation>
      <xs:documentation>A block of wrapping text. Use span children to style parts of it. Splits across pages between lines.</xs:documentation>
    </xs:annotation>
    <xs:complexType mixed="true">
      <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:element ref="span"/>
      </xs:choice>
      <xs:attribute name="font-size" type="TokenScaleOrPt"/>
      <xs:attribute name="font"      type="xs:string"/>
      <xs:attribute name="bold" type="xs:boolean">
        <xs:annotation>
          <xs:documentation>Use the bold face of the font. It applies to the 14 built-in fonts: Helvetica becomes Helvetica-Bold, Times-Roman becomes Times-Bold, Courier becomes Courier-Bold, and the oblique and italic faces their bold forms. A custom font has no bold face to pick, so name one in font.</xs:documentation>
        </xs:annotation>
      </xs:attribute>
      <xs:attribute name="color"     type="Color"/>
      <xs:attribute name="align"     type="TextAlignH"/>
      <xs:attribute name="width"     type="TokenScaleOrPt"/>
      <xs:attribute name="paginate"  type="Paginate"/>
      <xs:attribute name="debug"     type="xs:boolean"/>
      <xs:attributeGroup ref="DataBindingAttrs"/>
    </xs:complexType>
  </xs:element>

  <!-- ============================================================
       Table elements
  ============================================================ -->

  <!-- <td>: a table cell — container equivalent to stack -->
  <xs:element name="td">
    <xs:complexType>
      <xs:sequence>
        <xs:group ref="LayoutContent" minOccurs="0" maxOccurs="unbounded"/>
      </xs:sequence>
      <xs:attributeGroup ref="BoxAttrs"/>
      <xs:attribute name="align"  type="Align"/>
      <xs:attribute name="valign">
        <xs:simpleType>
          <xs:restriction base="xs:string">
            <xs:enumeration value="top"/>
            <xs:enumeration value="middle"/>
            <xs:enumeration value="bottom"/>
          </xs:restriction>
        </xs:simpleType>
      </xs:attribute>
    </xs:complexType>
  </xs:element>

  <!-- <thead>: header row — repeated at the top of each new page -->
  <xs:element name="thead">
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="td" minOccurs="1" maxOccurs="unbounded"/>
      </xs:sequence>
      <xs:attribute name="background" type="Color"/>
      <xs:attributeGroup ref="DataBindingAttrs"/>
    </xs:complexType>
  </xs:element>

  <!-- <tr>: a data row -->
  <xs:element name="tr">
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="td" minOccurs="1" maxOccurs="unbounded"/>
      </xs:sequence>
      <xs:attribute name="background" type="Color"/>
      <xs:attributeGroup ref="DataBindingAttrs"/>
    </xs:complexType>
  </xs:element>

  <!-- <table>: tabular layout with explicit column widths -->
  <xs:element name="table">
    <xs:annotation>
      <xs:documentation>Rows and cells in columns whose widths are set by cols. The thead row repeats at the top of every page, and rows move between pages whole.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="thead" minOccurs="0" maxOccurs="1"/>
        <xs:element ref="tr"    minOccurs="0" maxOccurs="unbounded"/>
      </xs:sequence>
      <!-- cols: space-separated column widths — fr, pt, % units.
           Example: "2fr 1fr 120pt 20%" -->
      <xs:attribute name="cols"       type="xs:string" use="required">
        <xs:annotation>
          <xs:documentation>Column widths, separated by spaces, in fr, pt or % units: for example 2fr 1fr 120pt 20%.</xs:documentation>
        </xs:annotation>
      </xs:attribute>
      <xs:attribute name="border"     type="BorderValue"/>
      <xs:attribute name="stripe"     type="Color"/>
      <xs:attribute name="gap"        type="TokenScaleOrPt"/>
      <xs:attribute name="padding"    type="SpacingOrToken"/>
      <xs:attribute name="background" type="Color"/>
      <xs:attribute name="width"      type="TokenScaleOrPt"/>
      <xs:attribute name="height"     type="HeightValue"/>
      <xs:attribute name="paginate"   type="Paginate"/>
      <xs:attribute name="debug"      type="xs:boolean"/>
      <xs:attributeGroup ref="DataBindingAttrs"/>
    </xs:complexType>
  </xs:element>

  <!-- ============================================================
       Form field element
  ============================================================ -->

  <xs:element name="field">
    <xs:complexType>
      <xs:attribute name="type" use="required">
        <xs:simpleType>
          <xs:restriction base="xs:string">
            <xs:enumeration value="text"/>
            <xs:enumeration value="checkbox"/>
            <xs:enumeration value="dropdown"/>
            <xs:enumeration value="radio"/>
            <xs:enumeration value="button"/>
          </xs:restriction>
        </xs:simpleType>
      </xs:attribute>
      <xs:attribute name="name"       type="xs:string" use="required"/>
      <xs:attribute name="value"      type="xs:string"/>
      <xs:attribute name="label"      type="xs:string"/>
      <xs:attribute name="options"    type="xs:string"/>
      <xs:attribute name="group"      type="xs:string"/>
      <xs:attribute name="checked"    type="xs:boolean"/>
      <xs:attribute name="required"   type="xs:boolean"/>
      <xs:attribute name="readonly"   type="xs:boolean"/>
      <xs:attribute name="max-len"    type="xs:positiveInteger"/>
      <xs:attribute name="action-url" type="xs:anyURI"/>
      <xs:attribute name="width"      type="TokenScaleOrPt"/>
      <xs:attribute name="height"     type="PtValue"/>
      <xs:attribute name="background" type="Color"/>
      <xs:attribute name="border"     type="BorderValue"/>
      <xs:attribute name="debug"      type="xs:boolean"/>
      <xs:attributeGroup ref="DataBindingAttrs"/>
    </xs:complexType>
  </xs:element>

</xs:schema>
