{
  "version": "appscreens.design.v1",
  "schema": {
    "type": "object",
    "description": "Editable one-page AppScreens design document. Apply against the saved baseline with current revision/hash; validate, render, inspect and use the existing export process. This is not a native scene replacement.",
    "properties": {
      "version": {
        "type": "string",
        "description": "Contract version.",
        "enum": [
          "appscreens.design.v1"
        ]
      },
      "screenshots": {
        "type": "array",
        "description": "Exactly the selected existing screenshot.",
        "items": {
          "type": "object",
          "description": "ONE existing saved screenshot. Project settings, root/global objects, languages, output targets and sibling pages are not replaceable through this document.",
          "properties": {
            "id": {
              "type": "string",
              "description": "Existing saved native UID. It is not an array index or an AI-generated identity.",
              "maxLength": 128,
              "minLength": 8,
              "pattern": "^[A-Za-z0-9_-]{8,128}$"
            },
            "background": {
              "anyOf": [
                {
                  "anyOf": [
                    {
                      "type": "object",
                      "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                      "properties": {
                        "rgba": {
                          "type": "array",
                          "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                          "items": {
                            "type": "number",
                            "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                            "minimum": 0,
                            "maximum": 255
                          },
                          "maxItems": 4,
                          "minItems": 4
                        }
                      },
                      "required": [
                        "rgba"
                      ],
                      "additionalProperties": false
                    },
                    {
                      "type": "object",
                      "description": "Gradient paint.",
                      "properties": {
                        "gradient": {
                          "type": "object",
                          "description": "Two-colour gradient, as the editor's gradient picker makes it.",
                          "properties": {
                            "style": {
                              "type": "string",
                              "description": "linear, or radial from the centre point.",
                              "enum": [
                                "linear",
                                "radial"
                              ]
                            },
                            "angle": {
                              "type": "number",
                              "description": "Linear: angle in degrees. Radial: radius as a percentage (1..100), centred in the painted area.",
                              "minimum": -360,
                              "maximum": 360
                            },
                            "from": {
                              "type": "object",
                              "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                              "properties": {
                                "rgba": {
                                  "type": "array",
                                  "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                  "items": {
                                    "type": "number",
                                    "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                    "minimum": 0,
                                    "maximum": 255
                                  },
                                  "maxItems": 4,
                                  "minItems": 4
                                }
                              },
                              "required": [
                                "rgba"
                              ],
                              "additionalProperties": false
                            },
                            "to": {
                              "type": "object",
                              "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                              "properties": {
                                "rgba": {
                                  "type": "array",
                                  "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                  "items": {
                                    "type": "number",
                                    "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                    "minimum": 0,
                                    "maximum": 255
                                  },
                                  "maxItems": 4,
                                  "minItems": 4
                                }
                              },
                              "required": [
                                "rgba"
                              ],
                              "additionalProperties": false
                            },
                            "stopFrom": {
                              "type": "number",
                              "description": "Where the first colour stops, 0..1.",
                              "minimum": 0,
                              "maximum": 1
                            },
                            "stopTo": {
                              "type": "number",
                              "description": "Where the second colour starts, 0..1.",
                              "minimum": 0,
                              "maximum": 1
                            }
                          },
                          "required": [
                            "style",
                            "angle",
                            "from",
                            "to",
                            "stopFrom",
                            "stopTo"
                          ],
                          "additionalProperties": false
                        }
                      },
                      "required": [
                        "gradient"
                      ],
                      "additionalProperties": false
                    }
                  ],
                  "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
                },
                {
                  "type": "null"
                }
              ],
              "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
            },
            "pattern": {
              "anyOf": [
                {
                  "type": "object",
                  "description": "Existing native tiled background motif. Registered library tiles remain native-only; other pattern controls are editable. This is not a positioned layer or broad landscape.",
                  "properties": {
                    "style": {
                      "type": "string",
                      "description": "Native motif mode.",
                      "enum": [
                        "dots",
                        "grid",
                        "diagonalLines",
                        "crosshatch",
                        "diamonds",
                        "waves",
                        "library"
                      ]
                    },
                    "color": {
                      "anyOf": [
                        {
                          "type": "object",
                          "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                          "properties": {
                            "rgba": {
                              "type": "array",
                              "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                              "items": {
                                "type": "number",
                                "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                "minimum": 0,
                                "maximum": 255
                              },
                              "maxItems": 4,
                              "minItems": 4
                            }
                          },
                          "required": [
                            "rgba"
                          ],
                          "additionalProperties": false
                        },
                        {
                          "type": "null"
                        }
                      ],
                      "description": "Opaque motif colour, alpha exactly 1. Do not set null: the native loader restores violet. Hide the pattern using opacity:0."
                    },
                    "opacity": {
                      "type": "number",
                      "description": "Percentage; use this, not color alpha, for transparency.",
                      "minimum": 0,
                      "maximum": 100
                    },
                    "size": {
                      "type": "number",
                      "description": "Native motif scale; motif width approx canvasWidth * .06 * size/100.",
                      "minimum": 10,
                      "maximum": 1000
                    },
                    "spacing": {
                      "type": "number",
                      "description": "Percentage of motif size.",
                      "minimum": 0,
                      "maximum": 300
                    },
                    "rotation": {
                      "type": "number",
                      "description": "Degrees.",
                      "minimum": -359,
                      "maximum": 359
                    }
                  },
                  "required": [
                    "style"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "null"
                }
              ],
              "description": "Existing native tiled background motif. Registered library tiles remain native-only; other pattern controls are editable. This is not a positioned layer or broad landscape."
            },
            "elements": {
              "type": "array",
              "description": "Existing element IDs/types only; add or remove elements with apply_project_changes. Order inside a layer follows array order.",
              "items": {
                "anyOf": [
                  {
                    "type": "object",
                    "description": "Native device frame and genuine app screenshot. Enum validity does not prove frame/appearance availability for every output target; preview and existing preflight remain mandatory.",
                    "properties": {
                      "type": {
                        "type": "string",
                        "description": "Component type.",
                        "enum": [
                          "device"
                        ]
                      },
                      "id": {
                        "type": "string",
                        "description": "Existing saved native UID. It is not an array index or an AI-generated identity.",
                        "maxLength": 128,
                        "minLength": 8,
                        "pattern": "^[A-Za-z0-9_-]{8,128}$"
                      },
                      "layer": {
                        "type": "integer",
                        "description": "Native layer, zero is bottom. Each layer is a vertical stack, as in the editor: array order is the stack order, the first element's y is the top of the stack and each later element starts where the one above ends (its y is derived). Put elements that should overlap or sit freely in separate layers. Empty layers are removed.",
                        "minimum": 0,
                        "maximum": 14
                      },
                      "location": {
                        "type": "object",
                        "description": "Native rectangle. In % mode 0.5 is half the canvas, NOT 50; x/y range -5..5, width/height 0..5. In px mode x/y range -100000..100000, width/height 0..100000. x/y locate the rectangle; anchor does not shift its origin.",
                        "properties": {
                          "x": {
                            "type": "number",
                            "description": "Rectangle X. Bounds depend on units.",
                            "minimum": -100000,
                            "maximum": 100000
                          },
                          "y": {
                            "type": "number",
                            "description": "Rectangle Y.",
                            "minimum": -100000,
                            "maximum": 100000
                          },
                          "width": {
                            "type": "number",
                            "description": "Rectangle width; zero-size existing objects are valid.",
                            "minimum": 0,
                            "maximum": 100000
                          },
                          "height": {
                            "type": "number",
                            "description": "Rectangle height.",
                            "minimum": 0,
                            "maximum": 100000
                          },
                          "units": {
                            "type": "string",
                            "description": "Native % fractions or px. Values are not converted when changing units.",
                            "enum": [
                              "px",
                              "%"
                            ]
                          },
                          "anchor": {
                            "type": "string",
                            "description": "Text uses this for vertical placement. For images, devices and shapes this legacy field is preserved but does not position content; use position instead.",
                            "enum": [
                              "topMiddle",
                              "topLeft",
                              "topRight",
                              "middle",
                              "middleLeft",
                              "middleRight",
                              "bottomMiddle",
                              "bottomLeft",
                              "bottomRight"
                            ]
                          }
                        },
                        "required": [
                          "x",
                          "y",
                          "width",
                          "height",
                          "units",
                          "anchor"
                        ],
                        "additionalProperties": false
                      },
                      "rotation": {
                        "type": "number",
                        "description": "Rotation in degrees, not radians; perspective is a device frame variant, not arbitrary 3D.",
                        "minimum": -359,
                        "maximum": 359
                      },
                      "opacity": {
                        "type": "integer",
                        "description": "Element opacity percentage. 0 is transparent and 100 is fully opaque. AppScreens stores 100 as its native null/default, but this document always exposes the effective percentage.",
                        "minimum": 0,
                        "maximum": 100
                      },
                      "slots": {
                        "type": "array",
                        "description": "Only existing explicit source assignments. Empty slots/fallbacks are not materialized. Each field/language/target combination must remain present and unchanged; only assetId can change.",
                        "items": {
                          "type": "object",
                          "description": "One source assignment.",
                          "properties": {
                            "field": {
                              "type": "string",
                              "description": "Original storage provenance.",
                              "enum": [
                                "base",
                                "translation",
                                "legacy"
                              ]
                            },
                            "language": {
                              "type": "string",
                              "description": "An existing language or target key. It cannot create languages or targets.",
                              "maxLength": 128,
                              "minLength": 1,
                              "pattern": "^[A-Za-z0-9_-]{1,128}$"
                            },
                            "targetId": {
                              "type": "string",
                              "description": "An existing language or target key. It cannot create languages or targets.",
                              "maxLength": 128,
                              "minLength": 1,
                              "pattern": "^[A-Za-z0-9_-]{1,128}$"
                            },
                            "assetId": {
                              "type": "string",
                              "description": "Approved stable asset ID. Never a URL, data URI, signed URL or token.",
                              "maxLength": 1024,
                              "minLength": 1
                            }
                          },
                          "required": [
                            "field",
                            "language",
                            "targetId",
                            "assetId"
                          ],
                          "additionalProperties": false
                        },
                        "maxItems": 500,
                        "minItems": 0
                      },
                      "fit": {
                        "type": "string",
                        "description": "Native contain or width-cover alignment. There is no cover/fill image mode.",
                        "enum": [
                          "contain",
                          "covertop",
                          "coverbottom",
                          "covercenter"
                        ]
                      },
                      "position": {
                        "type": "string",
                        "description": "Fitted source anchor.",
                        "enum": [
                          "topMiddle",
                          "topLeft",
                          "topRight",
                          "middle",
                          "middleLeft",
                          "middleRight",
                          "bottomMiddle",
                          "bottomLeft",
                          "bottomRight"
                        ]
                      },
                      "boundary": {
                        "type": "string",
                        "description": "How rotation meets the box. inside (the default): the rotated content is scaled down until its rotated bounds fit the unrotated box, so a tilted wide image draws smaller, by min(W / (w cos a + h sin a), H / (h cos a + w sin a)) for content w x h in box W x H. outside: the box itself turns and the content keeps its size, so its corners can pass the box. Use outside to tilt a card without shrinking it.",
                        "enum": [
                          "inside",
                          "outside"
                        ]
                      },
                      "shadow": {
                        "type": "object",
                        "description": "Native relative shadow. Rendering scales offsets/blur by 0.04 times its reference size, normally full canvas height, NOT pixels. Color null with global false disables the shadow; shadow null itself resets native defaults. Inherited shadows are preserved.",
                        "properties": {
                          "color": {
                            "anyOf": [
                              {
                                "type": "object",
                                "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                "properties": {
                                  "rgba": {
                                    "type": "array",
                                    "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                    "items": {
                                      "type": "number",
                                      "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                      "minimum": 0,
                                      "maximum": 255
                                    },
                                    "maxItems": 4,
                                    "minItems": 4
                                  }
                                },
                                "required": [
                                  "rgba"
                                ],
                                "additionalProperties": false
                              },
                              {
                                "type": "null"
                              }
                            ],
                            "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA."
                          },
                          "x": {
                            "type": "number",
                            "description": "Native horizontal offset. 0.125 is 0.5% of reference size.",
                            "minimum": -0.86,
                            "maximum": 0.86
                          },
                          "y": {
                            "type": "number",
                            "description": "Native vertical offset.",
                            "minimum": -0.86,
                            "maximum": 0.86
                          },
                          "blur": {
                            "type": "number",
                            "description": "Native blur; 0.25 is 1% of reference size.",
                            "minimum": 0,
                            "maximum": 2.5
                          },
                          "global": {
                            "type": "boolean",
                            "description": "True inherits the project shadow. False uses this explicit shadow."
                          }
                        },
                        "required": [
                          "color",
                          "x",
                          "y",
                          "blur",
                          "global"
                        ],
                        "additionalProperties": false
                      },
                      "frame": {
                        "type": "string",
                        "description": "Existing frame variants. Perspective variants are asset-defined, not arbitrary XYZ rotation.",
                        "enum": [
                          "full",
                          "dynamic",
                          "none",
                          "cover",
                          "warpleft",
                          "warpright",
                          "nonewarpleft",
                          "nonewarpright"
                        ]
                      },
                      "appearance": {
                        "type": "string",
                        "description": "Native appearance. Availability depends on the output target; inspect a rendered preview. Missing frame artwork uses the renderer fallback.",
                        "enum": [
                          "black",
                          "reallight",
                          "realgold",
                          "light",
                          "dark",
                          "granite",
                          "silver",
                          "mint",
                          "apple",
                          "earth",
                          "green",
                          "rose",
                          "strawberry",
                          "bluelagoon",
                          "space",
                          "berry",
                          "lemon",
                          "gold",
                          "coral"
                        ]
                      },
                      "orientation": {
                        "type": "string",
                        "description": "Device orientation.",
                        "enum": [
                          "portrait",
                          "landscapeleft",
                          "landscaperight"
                        ]
                      },
                      "blankWhenEmpty": {
                        "type": "boolean",
                        "description": "Show a plain dark screen when no app capture is available. False or unset shows the sample screenshot. Assigned captures take precedence. No asset is created or assigned by this setting."
                      },
                      "rounding": {
                        "anyOf": [
                          {
                            "type": "number",
                            "description": "Corner rounding, as in the editor: null is Auto (the frame's own screen corners) and 0 is None. Only dynamic and frameless variants use it.",
                            "minimum": 0,
                            "maximum": 0
                          },
                          {
                            "type": "null"
                          }
                        ],
                        "description": "Corner rounding, as in the editor: null is Auto (the frame's own screen corners) and 0 is None. Only dynamic and frameless variants use it."
                      },
                      "dynamicFrameColor": {
                        "anyOf": [
                          {
                            "type": "object",
                            "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                            "properties": {
                              "rgba": {
                                "type": "array",
                                "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                "items": {
                                  "type": "number",
                                  "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                  "minimum": 0,
                                  "maximum": 255
                                },
                                "maxItems": 4,
                                "minItems": 4
                              }
                            },
                            "required": [
                              "rgba"
                            ],
                            "additionalProperties": false
                          },
                          {
                            "type": "null"
                          }
                        ],
                        "description": "Visible solid dynamic frame colour. Changed null/alpha-zero would reset its native default and is rejected."
                      },
                      "dynamicFrameSize": {
                        "type": "number",
                        "description": "Fraction of shortest screenshot edge, 0..5%. Only dynamic frames use this.",
                        "minimum": 0,
                        "maximum": 0.05
                      },
                      "dynamicPadding": {
                        "type": "number",
                        "description": "Fraction of shortest screenshot edge, 0..5%. Only dynamic frames use this.",
                        "minimum": 0,
                        "maximum": 0.05
                      },
                      "dynamicPaddingColor": {
                        "anyOf": [
                          {
                            "type": "object",
                            "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                            "properties": {
                              "rgba": {
                                "type": "array",
                                "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                "items": {
                                  "type": "number",
                                  "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                  "minimum": 0,
                                  "maximum": 255
                                },
                                "maxItems": 4,
                                "minItems": 4
                              }
                            },
                            "required": [
                              "rgba"
                            ],
                            "additionalProperties": false
                          },
                          {
                            "type": "null"
                          }
                        ],
                        "description": "Solid dynamic padding colour, including alpha zero for transparent padding. Null restores the native default white at 20% opacity."
                      },
                      "dynamicInfill": {
                        "anyOf": [
                          {
                            "type": "object",
                            "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                            "properties": {
                              "rgba": {
                                "type": "array",
                                "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                "items": {
                                  "type": "number",
                                  "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                  "minimum": 0,
                                  "maximum": 255
                                },
                                "maxItems": 4,
                                "minItems": 4
                              }
                            },
                            "required": [
                              "rgba"
                            ],
                            "additionalProperties": false
                          },
                          {
                            "type": "null"
                          }
                        ],
                        "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA."
                      },
                      "displayDevices": {
                        "type": "array",
                        "description": "Overrides the project display for this frame on a selected output size. Use set_project_settings with patch.targets.targetOverrides for a display shared across the set. Set a layer override only when requested or when this frame needs a different device, such as a watch on a phone page. A \"global\" entry is this layer's fallback when it has no override for the output size. Preserve the list on unrelated edits. Send an empty list only to clear all overrides for this layer.",
                        "items": {
                          "type": "object",
                          "description": "One mapping.",
                          "properties": {
                            "targetId": {
                              "type": "string",
                              "description": "An existing language or target key. It cannot create languages or targets.",
                              "maxLength": 128,
                              "minLength": 1,
                              "pattern": "^[A-Za-z0-9_-]{1,128}$"
                            },
                            "displayDevice": {
                              "type": "string",
                              "description": "An existing language or target key. It cannot create languages or targets.",
                              "maxLength": 128,
                              "minLength": 1,
                              "pattern": "^[A-Za-z0-9_-]{1,128}$"
                            }
                          },
                          "required": [
                            "targetId",
                            "displayDevice"
                          ],
                          "additionalProperties": false
                        },
                        "maxItems": 100,
                        "minItems": 0
                      }
                    },
                    "required": [
                      "type",
                      "id",
                      "layer",
                      "opacity",
                      "slots"
                    ],
                    "additionalProperties": false
                  },
                  {
                    "type": "object",
                    "description": "Existing title/subtitle group. Common element shadow is not rendered on glyphs, so only title/subtitle block shadow is editable. Translation overrides/inactive locales stay native-only in this draft; use existing text tools for localization.",
                    "properties": {
                      "type": {
                        "type": "string",
                        "description": "Component type.",
                        "enum": [
                          "text"
                        ]
                      },
                      "id": {
                        "type": "string",
                        "description": "Existing saved native UID. It is not an array index or an AI-generated identity.",
                        "maxLength": 128,
                        "minLength": 8,
                        "pattern": "^[A-Za-z0-9_-]{8,128}$"
                      },
                      "layer": {
                        "type": "integer",
                        "description": "Native layer, zero is bottom. Each layer is a vertical stack, as in the editor: array order is the stack order, the first element's y is the top of the stack and each later element starts where the one above ends (its y is derived). Put elements that should overlap or sit freely in separate layers. Empty layers are removed.",
                        "minimum": 0,
                        "maximum": 14
                      },
                      "location": {
                        "type": "object",
                        "description": "Native rectangle. In % mode 0.5 is half the canvas, NOT 50; x/y range -5..5, width/height 0..5. In px mode x/y range -100000..100000, width/height 0..100000. x/y locate the rectangle; anchor does not shift its origin.",
                        "properties": {
                          "x": {
                            "type": "number",
                            "description": "Rectangle X. Bounds depend on units.",
                            "minimum": -100000,
                            "maximum": 100000
                          },
                          "y": {
                            "type": "number",
                            "description": "Rectangle Y.",
                            "minimum": -100000,
                            "maximum": 100000
                          },
                          "width": {
                            "type": "number",
                            "description": "Rectangle width; zero-size existing objects are valid.",
                            "minimum": 0,
                            "maximum": 100000
                          },
                          "height": {
                            "type": "number",
                            "description": "Rectangle height.",
                            "minimum": 0,
                            "maximum": 100000
                          },
                          "units": {
                            "type": "string",
                            "description": "Native % fractions or px. Values are not converted when changing units.",
                            "enum": [
                              "px",
                              "%"
                            ]
                          },
                          "anchor": {
                            "type": "string",
                            "description": "Vertical text placement: topMiddle, middle or bottomMiddle. Horizontal text alignment belongs to title.align/subtitle.align. Older side anchors are accepted and normalised to the corresponding vertical position.",
                            "enum": [
                              "topMiddle",
                              "middle",
                              "bottomMiddle"
                            ]
                          }
                        },
                        "required": [
                          "x",
                          "y",
                          "width",
                          "height",
                          "units",
                          "anchor"
                        ],
                        "additionalProperties": false
                      },
                      "rotation": {
                        "type": "number",
                        "description": "Rotation in degrees, not radians; perspective is a device frame variant, not arbitrary 3D.",
                        "minimum": -359,
                        "maximum": 359
                      },
                      "opacity": {
                        "type": "integer",
                        "description": "Element opacity percentage. 0 is transparent and 100 is fully opaque. AppScreens stores 100 as its native null/default, but this document always exposes the effective percentage.",
                        "minimum": 0,
                        "maximum": 100
                      },
                      "title": {
                        "type": "object",
                        "description": "Existing native title/subtitle block. Only exported properties are editable. Native inline gradient/highlight and unsupported ops remain unchanged. Fonts are names from the page or list_fonts, without source URLs.",
                        "properties": {
                          "runs": {
                            "type": "array",
                            "description": "Existing rich runs, same number/order; text, bold/italic/underline and colour can change.",
                            "items": {
                              "type": "object",
                              "description": "Literal native text run, including intentional newlines. Existing run count/order stays fixed so unrepresented inline formatting is preserved. No HTML, embeds, Quill commands or automatic terminal newline conversion.",
                              "properties": {
                                "text": {
                                  "type": "string",
                                  "description": "Literal Unicode text, never HTML. A title or subtitle has at most 250 characters across all runs, excluding its final Quill newline.",
                                  "maxLength": 251
                                },
                                "bold": {
                                  "type": "boolean",
                                  "description": "Inline bold."
                                },
                                "italic": {
                                  "type": "boolean",
                                  "description": "Inline italic."
                                },
                                "underline": {
                                  "type": "boolean",
                                  "description": "Inline underline."
                                },
                                "color": {
                                  "anyOf": [
                                    {
                                      "type": "object",
                                      "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                      "properties": {
                                        "rgba": {
                                          "type": "array",
                                          "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                          "items": {
                                            "type": "number",
                                            "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                            "minimum": 0,
                                            "maximum": 255
                                          },
                                          "maxItems": 4,
                                          "minItems": 4
                                        }
                                      },
                                      "required": [
                                        "rgba"
                                      ],
                                      "additionalProperties": false
                                    },
                                    {
                                      "type": "null"
                                    }
                                  ],
                                  "description": "Inline solid colour of this run; null uses the block colour. Omitted when the run has a gradient or other native paint, which stays unchanged."
                                }
                              },
                              "required": [
                                "text",
                                "bold",
                                "italic",
                                "underline"
                              ],
                              "additionalProperties": false
                            },
                            "maxItems": 500,
                            "minItems": 0
                          },
                          "font": {
                            "type": "string",
                            "description": "Font family name: one already on the page, or a Google or account font from list_fonts. Never a font URL. Text with global true follows the project font and can't take its own, as in the editor: send global: false with the font.",
                            "maxLength": 200
                          },
                          "global": {
                            "type": "boolean",
                            "description": "Follow the project's title or subtitle font (set in project settings). When true, font is this text's own font, used again if global is turned off."
                          },
                          "maxFontSize": {
                            "type": "number",
                            "description": "Fraction of full canvas width. Effective only when fontSizeLock is false, which takes the block out of the matched set size. May be supplied when a locked baseline omitted this native setting.",
                            "minimum": 0.005,
                            "maximum": 1
                          },
                          "fontSizeLock": {
                            "type": "boolean",
                            "description": "Match text size (recommended, the template default): true gives every matched caption the size of the smallest one that fits, per language and output size, so the set stays consistent. False enables maxFontSize for this block only."
                          },
                          "multiline": {
                            "type": "boolean",
                            "description": "Allow native multiline layout."
                          },
                          "align": {
                            "type": "string",
                            "description": "Block alignment, not an inline operation.",
                            "enum": [
                              "left",
                              "right",
                              "center"
                            ]
                          },
                          "color": {
                            "anyOf": [
                              {
                                "type": "object",
                                "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                "properties": {
                                  "rgba": {
                                    "type": "array",
                                    "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                    "items": {
                                      "type": "number",
                                      "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                      "minimum": 0,
                                      "maximum": 255
                                    },
                                    "maxItems": 4,
                                    "minItems": 4
                                  }
                                },
                                "required": [
                                  "rgba"
                                ],
                                "additionalProperties": false
                              },
                              {
                                "type": "null"
                              }
                            ],
                            "description": "Opaque or visible solid text colour. Changed null/alpha-zero is rejected because native serialization restores its default instead of preserving transparency."
                          },
                          "lineHeight": {
                            "type": "number",
                            "description": "Native line-height multiplier.",
                            "minimum": 0.01,
                            "maximum": 3
                          },
                          "letterSpacing": {
                            "type": "number",
                            "description": "Native fraction of font size, not pixels.",
                            "minimum": 0,
                            "maximum": 0.25
                          },
                          "highlightPaddingX": {
                            "type": "number",
                            "description": "Fraction of font size.",
                            "minimum": 0,
                            "maximum": 1
                          },
                          "highlightPaddingY": {
                            "anyOf": [
                              {
                                "type": "number",
                                "description": "Fraction of font size. Null inherits X.",
                                "minimum": 0,
                                "maximum": 1
                              },
                              {
                                "type": "null"
                              }
                            ],
                            "description": "Fraction of font size. Null inherits X."
                          },
                          "highlightRounding": {
                            "type": "number",
                            "description": "Fraction of highlight height.",
                            "minimum": 0,
                            "maximum": 0.5
                          },
                          "shadow": {
                            "type": "object",
                            "description": "Native relative shadow. Rendering scales offsets/blur by 0.04 times its reference size, normally full canvas height, NOT pixels. Color null with global false disables the shadow; shadow null itself resets native defaults. Inherited shadows are preserved.",
                            "properties": {
                              "color": {
                                "anyOf": [
                                  {
                                    "type": "object",
                                    "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                    "properties": {
                                      "rgba": {
                                        "type": "array",
                                        "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                        "items": {
                                          "type": "number",
                                          "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                          "minimum": 0,
                                          "maximum": 255
                                        },
                                        "maxItems": 4,
                                        "minItems": 4
                                      }
                                    },
                                    "required": [
                                      "rgba"
                                    ],
                                    "additionalProperties": false
                                  },
                                  {
                                    "type": "null"
                                  }
                                ],
                                "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA."
                              },
                              "x": {
                                "type": "number",
                                "description": "Native horizontal offset. 0.125 is 0.5% of reference size.",
                                "minimum": -0.86,
                                "maximum": 0.86
                              },
                              "y": {
                                "type": "number",
                                "description": "Native vertical offset.",
                                "minimum": -0.86,
                                "maximum": 0.86
                              },
                              "blur": {
                                "type": "number",
                                "description": "Native blur; 0.25 is 1% of reference size.",
                                "minimum": 0,
                                "maximum": 2.5
                              },
                              "global": {
                                "type": "boolean",
                                "description": "True inherits the project shadow. False uses this explicit shadow."
                              }
                            },
                            "required": [
                              "color",
                              "x",
                              "y",
                              "blur",
                              "global"
                            ],
                            "additionalProperties": false
                          }
                        },
                        "required": [],
                        "additionalProperties": false
                      },
                      "subtitle": {
                        "anyOf": [
                          {
                            "type": "object",
                            "description": "Existing native title/subtitle block. Only exported properties are editable. Native inline gradient/highlight and unsupported ops remain unchanged. Fonts are names from the page or list_fonts, without source URLs.",
                            "properties": {
                              "runs": {
                                "type": "array",
                                "description": "Existing rich runs, same number/order; text, bold/italic/underline and colour can change.",
                                "items": {
                                  "type": "object",
                                  "description": "Literal native text run, including intentional newlines. Existing run count/order stays fixed so unrepresented inline formatting is preserved. No HTML, embeds, Quill commands or automatic terminal newline conversion.",
                                  "properties": {
                                    "text": {
                                      "type": "string",
                                      "description": "Literal Unicode text, never HTML. A title or subtitle has at most 250 characters across all runs, excluding its final Quill newline.",
                                      "maxLength": 251
                                    },
                                    "bold": {
                                      "type": "boolean",
                                      "description": "Inline bold."
                                    },
                                    "italic": {
                                      "type": "boolean",
                                      "description": "Inline italic."
                                    },
                                    "underline": {
                                      "type": "boolean",
                                      "description": "Inline underline."
                                    },
                                    "color": {
                                      "anyOf": [
                                        {
                                          "type": "object",
                                          "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                          "properties": {
                                            "rgba": {
                                              "type": "array",
                                              "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                              "items": {
                                                "type": "number",
                                                "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                                "minimum": 0,
                                                "maximum": 255
                                              },
                                              "maxItems": 4,
                                              "minItems": 4
                                            }
                                          },
                                          "required": [
                                            "rgba"
                                          ],
                                          "additionalProperties": false
                                        },
                                        {
                                          "type": "null"
                                        }
                                      ],
                                      "description": "Inline solid colour of this run; null uses the block colour. Omitted when the run has a gradient or other native paint, which stays unchanged."
                                    }
                                  },
                                  "required": [
                                    "text",
                                    "bold",
                                    "italic",
                                    "underline"
                                  ],
                                  "additionalProperties": false
                                },
                                "maxItems": 500,
                                "minItems": 0
                              },
                              "font": {
                                "type": "string",
                                "description": "Font family name: one already on the page, or a Google or account font from list_fonts. Never a font URL. Text with global true follows the project font and can't take its own, as in the editor: send global: false with the font.",
                                "maxLength": 200
                              },
                              "global": {
                                "type": "boolean",
                                "description": "Follow the project's title or subtitle font (set in project settings). When true, font is this text's own font, used again if global is turned off."
                              },
                              "maxFontSize": {
                                "type": "number",
                                "description": "Fraction of full canvas width. Effective only when fontSizeLock is false, which takes the block out of the matched set size. May be supplied when a locked baseline omitted this native setting.",
                                "minimum": 0.005,
                                "maximum": 1
                              },
                              "fontSizeLock": {
                                "type": "boolean",
                                "description": "Match text size (recommended, the template default): true gives every matched caption the size of the smallest one that fits, per language and output size, so the set stays consistent. False enables maxFontSize for this block only."
                              },
                              "multiline": {
                                "type": "boolean",
                                "description": "Allow native multiline layout."
                              },
                              "align": {
                                "type": "string",
                                "description": "Block alignment, not an inline operation.",
                                "enum": [
                                  "left",
                                  "right",
                                  "center"
                                ]
                              },
                              "color": {
                                "anyOf": [
                                  {
                                    "type": "object",
                                    "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                    "properties": {
                                      "rgba": {
                                        "type": "array",
                                        "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                        "items": {
                                          "type": "number",
                                          "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                          "minimum": 0,
                                          "maximum": 255
                                        },
                                        "maxItems": 4,
                                        "minItems": 4
                                      }
                                    },
                                    "required": [
                                      "rgba"
                                    ],
                                    "additionalProperties": false
                                  },
                                  {
                                    "type": "null"
                                  }
                                ],
                                "description": "Opaque or visible solid text colour. Changed null/alpha-zero is rejected because native serialization restores its default instead of preserving transparency."
                              },
                              "lineHeight": {
                                "type": "number",
                                "description": "Native line-height multiplier.",
                                "minimum": 0.01,
                                "maximum": 3
                              },
                              "letterSpacing": {
                                "type": "number",
                                "description": "Native fraction of font size, not pixels.",
                                "minimum": 0,
                                "maximum": 0.25
                              },
                              "highlightPaddingX": {
                                "type": "number",
                                "description": "Fraction of font size.",
                                "minimum": 0,
                                "maximum": 1
                              },
                              "highlightPaddingY": {
                                "anyOf": [
                                  {
                                    "type": "number",
                                    "description": "Fraction of font size. Null inherits X.",
                                    "minimum": 0,
                                    "maximum": 1
                                  },
                                  {
                                    "type": "null"
                                  }
                                ],
                                "description": "Fraction of font size. Null inherits X."
                              },
                              "highlightRounding": {
                                "type": "number",
                                "description": "Fraction of highlight height.",
                                "minimum": 0,
                                "maximum": 0.5
                              },
                              "shadow": {
                                "type": "object",
                                "description": "Native relative shadow. Rendering scales offsets/blur by 0.04 times its reference size, normally full canvas height, NOT pixels. Color null with global false disables the shadow; shadow null itself resets native defaults. Inherited shadows are preserved.",
                                "properties": {
                                  "color": {
                                    "anyOf": [
                                      {
                                        "type": "object",
                                        "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                        "properties": {
                                          "rgba": {
                                            "type": "array",
                                            "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                            "items": {
                                              "type": "number",
                                              "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                              "minimum": 0,
                                              "maximum": 255
                                            },
                                            "maxItems": 4,
                                            "minItems": 4
                                          }
                                        },
                                        "required": [
                                          "rgba"
                                        ],
                                        "additionalProperties": false
                                      },
                                      {
                                        "type": "null"
                                      }
                                    ],
                                    "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA."
                                  },
                                  "x": {
                                    "type": "number",
                                    "description": "Native horizontal offset. 0.125 is 0.5% of reference size.",
                                    "minimum": -0.86,
                                    "maximum": 0.86
                                  },
                                  "y": {
                                    "type": "number",
                                    "description": "Native vertical offset.",
                                    "minimum": -0.86,
                                    "maximum": 0.86
                                  },
                                  "blur": {
                                    "type": "number",
                                    "description": "Native blur; 0.25 is 1% of reference size.",
                                    "minimum": 0,
                                    "maximum": 2.5
                                  },
                                  "global": {
                                    "type": "boolean",
                                    "description": "True inherits the project shadow. False uses this explicit shadow."
                                  }
                                },
                                "required": [
                                  "color",
                                  "x",
                                  "y",
                                  "blur",
                                  "global"
                                ],
                                "additionalProperties": false
                              }
                            },
                            "required": [],
                            "additionalProperties": false
                          },
                          {
                            "type": "null"
                          }
                        ],
                        "description": "Existing native title/subtitle block. Only exported properties are editable. Native inline gradient/highlight and unsupported ops remain unchanged. Fonts are names from the page or list_fonts, without source URLs."
                      },
                      "spacing": {
                        "type": "number",
                        "description": "Gap as fraction of fitted title/subtitle group height.",
                        "minimum": 0,
                        "maximum": 1
                      },
                      "titleRatio": {
                        "type": "number",
                        "description": "Title share of group height; at most 0.99 with a subtitle, 1 is valid without a subtitle.",
                        "minimum": 0,
                        "maximum": 1
                      },
                      "decoration": {
                        "type": "string",
                        "description": "The editor's text decoration. Use laurels for award captions, geometric styles for labels and speech bubbles for quotes. Start with laurelCompactTight for a short award caption. Choose a wider compact style if the caption needs more room. Use none to clear the decoration. Use only verified award and rating claims.",
                        "enum": [
                          "none",
                          "laurelCompactSquare",
                          "laurelCompactTight",
                          "laurelCompactWide",
                          "laurelCompactWider",
                          "laurelTight",
                          "laurelWide",
                          "laurelWider",
                          "rectangle",
                          "rectangleRounded",
                          "ovalRounded",
                          "square",
                          "squareRounded",
                          "circle",
                          "badge",
                          "commentLeft",
                          "commentRight",
                          "chatBubbleLeft",
                          "chatBubbleRight",
                          "starBackground"
                        ]
                      },
                      "decorationFill": {
                        "anyOf": [
                          {
                            "anyOf": [
                              {
                                "type": "object",
                                "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                "properties": {
                                  "rgba": {
                                    "type": "array",
                                    "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                    "items": {
                                      "type": "number",
                                      "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                      "minimum": 0,
                                      "maximum": 255
                                    },
                                    "maxItems": 4,
                                    "minItems": 4
                                  }
                                },
                                "required": [
                                  "rgba"
                                ],
                                "additionalProperties": false
                              },
                              {
                                "type": "object",
                                "description": "Gradient paint.",
                                "properties": {
                                  "gradient": {
                                    "type": "object",
                                    "description": "Two-colour gradient, as the editor's gradient picker makes it.",
                                    "properties": {
                                      "style": {
                                        "type": "string",
                                        "description": "linear, or radial from the centre point.",
                                        "enum": [
                                          "linear",
                                          "radial"
                                        ]
                                      },
                                      "angle": {
                                        "type": "number",
                                        "description": "Linear: angle in degrees. Radial: radius as a percentage (1..100), centred in the painted area.",
                                        "minimum": -360,
                                        "maximum": 360
                                      },
                                      "from": {
                                        "type": "object",
                                        "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                        "properties": {
                                          "rgba": {
                                            "type": "array",
                                            "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                            "items": {
                                              "type": "number",
                                              "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                              "minimum": 0,
                                              "maximum": 255
                                            },
                                            "maxItems": 4,
                                            "minItems": 4
                                          }
                                        },
                                        "required": [
                                          "rgba"
                                        ],
                                        "additionalProperties": false
                                      },
                                      "to": {
                                        "type": "object",
                                        "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                        "properties": {
                                          "rgba": {
                                            "type": "array",
                                            "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                            "items": {
                                              "type": "number",
                                              "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                              "minimum": 0,
                                              "maximum": 255
                                            },
                                            "maxItems": 4,
                                            "minItems": 4
                                          }
                                        },
                                        "required": [
                                          "rgba"
                                        ],
                                        "additionalProperties": false
                                      },
                                      "stopFrom": {
                                        "type": "number",
                                        "description": "Where the first colour stops, 0..1.",
                                        "minimum": 0,
                                        "maximum": 1
                                      },
                                      "stopTo": {
                                        "type": "number",
                                        "description": "Where the second colour starts, 0..1.",
                                        "minimum": 0,
                                        "maximum": 1
                                      }
                                    },
                                    "required": [
                                      "style",
                                      "angle",
                                      "from",
                                      "to",
                                      "stopFrom",
                                      "stopTo"
                                    ],
                                    "additionalProperties": false
                                  }
                                },
                                "required": [
                                  "gradient"
                                ],
                                "additionalProperties": false
                              }
                            ],
                            "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
                          },
                          {
                            "type": "null"
                          }
                        ],
                        "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
                      },
                      "decorationStroke": {
                        "anyOf": [
                          {
                            "anyOf": [
                              {
                                "type": "object",
                                "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                "properties": {
                                  "rgba": {
                                    "type": "array",
                                    "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                    "items": {
                                      "type": "number",
                                      "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                      "minimum": 0,
                                      "maximum": 255
                                    },
                                    "maxItems": 4,
                                    "minItems": 4
                                  }
                                },
                                "required": [
                                  "rgba"
                                ],
                                "additionalProperties": false
                              },
                              {
                                "type": "object",
                                "description": "Gradient paint.",
                                "properties": {
                                  "gradient": {
                                    "type": "object",
                                    "description": "Two-colour gradient, as the editor's gradient picker makes it.",
                                    "properties": {
                                      "style": {
                                        "type": "string",
                                        "description": "linear, or radial from the centre point.",
                                        "enum": [
                                          "linear",
                                          "radial"
                                        ]
                                      },
                                      "angle": {
                                        "type": "number",
                                        "description": "Linear: angle in degrees. Radial: radius as a percentage (1..100), centred in the painted area.",
                                        "minimum": -360,
                                        "maximum": 360
                                      },
                                      "from": {
                                        "type": "object",
                                        "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                        "properties": {
                                          "rgba": {
                                            "type": "array",
                                            "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                            "items": {
                                              "type": "number",
                                              "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                              "minimum": 0,
                                              "maximum": 255
                                            },
                                            "maxItems": 4,
                                            "minItems": 4
                                          }
                                        },
                                        "required": [
                                          "rgba"
                                        ],
                                        "additionalProperties": false
                                      },
                                      "to": {
                                        "type": "object",
                                        "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                        "properties": {
                                          "rgba": {
                                            "type": "array",
                                            "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                            "items": {
                                              "type": "number",
                                              "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                              "minimum": 0,
                                              "maximum": 255
                                            },
                                            "maxItems": 4,
                                            "minItems": 4
                                          }
                                        },
                                        "required": [
                                          "rgba"
                                        ],
                                        "additionalProperties": false
                                      },
                                      "stopFrom": {
                                        "type": "number",
                                        "description": "Where the first colour stops, 0..1.",
                                        "minimum": 0,
                                        "maximum": 1
                                      },
                                      "stopTo": {
                                        "type": "number",
                                        "description": "Where the second colour starts, 0..1.",
                                        "minimum": 0,
                                        "maximum": 1
                                      }
                                    },
                                    "required": [
                                      "style",
                                      "angle",
                                      "from",
                                      "to",
                                      "stopFrom",
                                      "stopTo"
                                    ],
                                    "additionalProperties": false
                                  }
                                },
                                "required": [
                                  "gradient"
                                ],
                                "additionalProperties": false
                              }
                            ],
                            "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
                          },
                          {
                            "type": "null"
                          }
                        ],
                        "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
                      },
                      "decorationStrokeWidth": {
                        "type": "number",
                        "description": "Fraction of decoration image height, not pixels. 0.01 is 1%.",
                        "minimum": 0,
                        "maximum": 0.2
                      },
                      "decorationShadow": {
                        "type": "object",
                        "description": "Native relative shadow. Rendering scales offsets/blur by 0.04 times its reference size, normally full canvas height, NOT pixels. Color null with global false disables the shadow; shadow null itself resets native defaults. Inherited shadows are preserved.",
                        "properties": {
                          "color": {
                            "anyOf": [
                              {
                                "type": "object",
                                "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                "properties": {
                                  "rgba": {
                                    "type": "array",
                                    "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                    "items": {
                                      "type": "number",
                                      "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                      "minimum": 0,
                                      "maximum": 255
                                    },
                                    "maxItems": 4,
                                    "minItems": 4
                                  }
                                },
                                "required": [
                                  "rgba"
                                ],
                                "additionalProperties": false
                              },
                              {
                                "type": "null"
                              }
                            ],
                            "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA."
                          },
                          "x": {
                            "type": "number",
                            "description": "Native horizontal offset. 0.125 is 0.5% of reference size.",
                            "minimum": -0.86,
                            "maximum": 0.86
                          },
                          "y": {
                            "type": "number",
                            "description": "Native vertical offset.",
                            "minimum": -0.86,
                            "maximum": 0.86
                          },
                          "blur": {
                            "type": "number",
                            "description": "Native blur; 0.25 is 1% of reference size.",
                            "minimum": 0,
                            "maximum": 2.5
                          },
                          "global": {
                            "type": "boolean",
                            "description": "True inherits the project shadow. False uses this explicit shadow."
                          }
                        },
                        "required": [
                          "color",
                          "x",
                          "y",
                          "blur",
                          "global"
                        ],
                        "additionalProperties": false
                      }
                    },
                    "required": [
                      "type",
                      "id",
                      "layer",
                      "opacity"
                    ],
                    "additionalProperties": false
                  },
                  {
                    "type": "object",
                    "description": "Editable native geometry and paint. Fill and stroke can be solid or a gradient.",
                    "properties": {
                      "type": {
                        "type": "string",
                        "description": "Component type.",
                        "enum": [
                          "shape"
                        ]
                      },
                      "id": {
                        "type": "string",
                        "description": "Existing saved native UID. It is not an array index or an AI-generated identity.",
                        "maxLength": 128,
                        "minLength": 8,
                        "pattern": "^[A-Za-z0-9_-]{8,128}$"
                      },
                      "layer": {
                        "type": "integer",
                        "description": "Native layer, zero is bottom. Each layer is a vertical stack, as in the editor: array order is the stack order, the first element's y is the top of the stack and each later element starts where the one above ends (its y is derived). Put elements that should overlap or sit freely in separate layers. Empty layers are removed.",
                        "minimum": 0,
                        "maximum": 14
                      },
                      "location": {
                        "type": "object",
                        "description": "Native rectangle. In % mode 0.5 is half the canvas, NOT 50; x/y range -5..5, width/height 0..5. In px mode x/y range -100000..100000, width/height 0..100000. x/y locate the rectangle; anchor does not shift its origin.",
                        "properties": {
                          "x": {
                            "type": "number",
                            "description": "Rectangle X. Bounds depend on units.",
                            "minimum": -100000,
                            "maximum": 100000
                          },
                          "y": {
                            "type": "number",
                            "description": "Rectangle Y.",
                            "minimum": -100000,
                            "maximum": 100000
                          },
                          "width": {
                            "type": "number",
                            "description": "Rectangle width; zero-size existing objects are valid.",
                            "minimum": 0,
                            "maximum": 100000
                          },
                          "height": {
                            "type": "number",
                            "description": "Rectangle height.",
                            "minimum": 0,
                            "maximum": 100000
                          },
                          "units": {
                            "type": "string",
                            "description": "Native % fractions or px. Values are not converted when changing units.",
                            "enum": [
                              "px",
                              "%"
                            ]
                          },
                          "anchor": {
                            "type": "string",
                            "description": "Text uses this for vertical placement. For images, devices and shapes this legacy field is preserved but does not position content; use position instead.",
                            "enum": [
                              "topMiddle",
                              "topLeft",
                              "topRight",
                              "middle",
                              "middleLeft",
                              "middleRight",
                              "bottomMiddle",
                              "bottomLeft",
                              "bottomRight"
                            ]
                          }
                        },
                        "required": [
                          "x",
                          "y",
                          "width",
                          "height",
                          "units",
                          "anchor"
                        ],
                        "additionalProperties": false
                      },
                      "rotation": {
                        "type": "number",
                        "description": "Rotation in degrees, not radians; perspective is a device frame variant, not arbitrary 3D.",
                        "minimum": -359,
                        "maximum": 359
                      },
                      "opacity": {
                        "type": "integer",
                        "description": "Element opacity percentage. 0 is transparent and 100 is fully opaque. AppScreens stores 100 as its native null/default, but this document always exposes the effective percentage.",
                        "minimum": 0,
                        "maximum": 100
                      },
                      "shadow": {
                        "type": "object",
                        "description": "Native relative shadow. Rendering scales offsets/blur by 0.04 times its reference size, normally full canvas height, NOT pixels. Color null with global false disables the shadow; shadow null itself resets native defaults. Inherited shadows are preserved.",
                        "properties": {
                          "color": {
                            "anyOf": [
                              {
                                "type": "object",
                                "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                "properties": {
                                  "rgba": {
                                    "type": "array",
                                    "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                    "items": {
                                      "type": "number",
                                      "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                      "minimum": 0,
                                      "maximum": 255
                                    },
                                    "maxItems": 4,
                                    "minItems": 4
                                  }
                                },
                                "required": [
                                  "rgba"
                                ],
                                "additionalProperties": false
                              },
                              {
                                "type": "null"
                              }
                            ],
                            "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA."
                          },
                          "x": {
                            "type": "number",
                            "description": "Native horizontal offset. 0.125 is 0.5% of reference size.",
                            "minimum": -0.86,
                            "maximum": 0.86
                          },
                          "y": {
                            "type": "number",
                            "description": "Native vertical offset.",
                            "minimum": -0.86,
                            "maximum": 0.86
                          },
                          "blur": {
                            "type": "number",
                            "description": "Native blur; 0.25 is 1% of reference size.",
                            "minimum": 0,
                            "maximum": 2.5
                          },
                          "global": {
                            "type": "boolean",
                            "description": "True inherits the project shadow. False uses this explicit shadow."
                          }
                        },
                        "required": [
                          "color",
                          "x",
                          "y",
                          "blur",
                          "global"
                        ],
                        "additionalProperties": false
                      },
                      "shape": {
                        "type": "string",
                        "description": "Native shape.",
                        "enum": [
                          "rectangle",
                          "square",
                          "circle",
                          "ellipse",
                          "triangle",
                          "line"
                        ]
                      },
                      "fit": {
                        "type": "string",
                        "description": "Native shape sizing mode, including fill.",
                        "enum": [
                          "fill",
                          "contain",
                          "covertop",
                          "coverbottom",
                          "covercenter"
                        ]
                      },
                      "lineDirection": {
                        "type": "string",
                        "description": "Line shapes only.",
                        "enum": [
                          "horizontal",
                          "vertical"
                        ]
                      },
                      "position": {
                        "type": "string",
                        "description": "Content anchor. Horizontal lines use topMiddle/middle/bottomMiddle; vertical lines use middleLeft/middle/middleRight. Other saved line anchors render at the centre.",
                        "enum": [
                          "topMiddle",
                          "topLeft",
                          "topRight",
                          "middle",
                          "middleLeft",
                          "middleRight",
                          "bottomMiddle",
                          "bottomLeft",
                          "bottomRight"
                        ]
                      },
                      "boundary": {
                        "type": "string",
                        "description": "How rotation meets the box. inside (the default): the rotated content is scaled down until its rotated bounds fit the unrotated box, so a tilted wide image draws smaller, by min(W / (w cos a + h sin a), H / (h cos a + w sin a)) for content w x h in box W x H. outside: the box itself turns and the content keeps its size, so its corners can pass the box. Use outside to tilt a card without shrinking it.",
                        "enum": [
                          "inside",
                          "outside"
                        ]
                      },
                      "fill": {
                        "anyOf": [
                          {
                            "anyOf": [
                              {
                                "type": "object",
                                "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                "properties": {
                                  "rgba": {
                                    "type": "array",
                                    "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                    "items": {
                                      "type": "number",
                                      "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                      "minimum": 0,
                                      "maximum": 255
                                    },
                                    "maxItems": 4,
                                    "minItems": 4
                                  }
                                },
                                "required": [
                                  "rgba"
                                ],
                                "additionalProperties": false
                              },
                              {
                                "type": "object",
                                "description": "Gradient paint.",
                                "properties": {
                                  "gradient": {
                                    "type": "object",
                                    "description": "Two-colour gradient, as the editor's gradient picker makes it.",
                                    "properties": {
                                      "style": {
                                        "type": "string",
                                        "description": "linear, or radial from the centre point.",
                                        "enum": [
                                          "linear",
                                          "radial"
                                        ]
                                      },
                                      "angle": {
                                        "type": "number",
                                        "description": "Linear: angle in degrees. Radial: radius as a percentage (1..100), centred in the painted area.",
                                        "minimum": -360,
                                        "maximum": 360
                                      },
                                      "from": {
                                        "type": "object",
                                        "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                        "properties": {
                                          "rgba": {
                                            "type": "array",
                                            "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                            "items": {
                                              "type": "number",
                                              "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                              "minimum": 0,
                                              "maximum": 255
                                            },
                                            "maxItems": 4,
                                            "minItems": 4
                                          }
                                        },
                                        "required": [
                                          "rgba"
                                        ],
                                        "additionalProperties": false
                                      },
                                      "to": {
                                        "type": "object",
                                        "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                        "properties": {
                                          "rgba": {
                                            "type": "array",
                                            "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                            "items": {
                                              "type": "number",
                                              "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                              "minimum": 0,
                                              "maximum": 255
                                            },
                                            "maxItems": 4,
                                            "minItems": 4
                                          }
                                        },
                                        "required": [
                                          "rgba"
                                        ],
                                        "additionalProperties": false
                                      },
                                      "stopFrom": {
                                        "type": "number",
                                        "description": "Where the first colour stops, 0..1.",
                                        "minimum": 0,
                                        "maximum": 1
                                      },
                                      "stopTo": {
                                        "type": "number",
                                        "description": "Where the second colour starts, 0..1.",
                                        "minimum": 0,
                                        "maximum": 1
                                      }
                                    },
                                    "required": [
                                      "style",
                                      "angle",
                                      "from",
                                      "to",
                                      "stopFrom",
                                      "stopTo"
                                    ],
                                    "additionalProperties": false
                                  }
                                },
                                "required": [
                                  "gradient"
                                ],
                                "additionalProperties": false
                              }
                            ],
                            "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
                          },
                          {
                            "type": "null"
                          }
                        ],
                        "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
                      },
                      "stroke": {
                        "anyOf": [
                          {
                            "anyOf": [
                              {
                                "type": "object",
                                "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                "properties": {
                                  "rgba": {
                                    "type": "array",
                                    "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                    "items": {
                                      "type": "number",
                                      "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                      "minimum": 0,
                                      "maximum": 255
                                    },
                                    "maxItems": 4,
                                    "minItems": 4
                                  }
                                },
                                "required": [
                                  "rgba"
                                ],
                                "additionalProperties": false
                              },
                              {
                                "type": "object",
                                "description": "Gradient paint.",
                                "properties": {
                                  "gradient": {
                                    "type": "object",
                                    "description": "Two-colour gradient, as the editor's gradient picker makes it.",
                                    "properties": {
                                      "style": {
                                        "type": "string",
                                        "description": "linear, or radial from the centre point.",
                                        "enum": [
                                          "linear",
                                          "radial"
                                        ]
                                      },
                                      "angle": {
                                        "type": "number",
                                        "description": "Linear: angle in degrees. Radial: radius as a percentage (1..100), centred in the painted area.",
                                        "minimum": -360,
                                        "maximum": 360
                                      },
                                      "from": {
                                        "type": "object",
                                        "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                        "properties": {
                                          "rgba": {
                                            "type": "array",
                                            "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                            "items": {
                                              "type": "number",
                                              "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                              "minimum": 0,
                                              "maximum": 255
                                            },
                                            "maxItems": 4,
                                            "minItems": 4
                                          }
                                        },
                                        "required": [
                                          "rgba"
                                        ],
                                        "additionalProperties": false
                                      },
                                      "to": {
                                        "type": "object",
                                        "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                        "properties": {
                                          "rgba": {
                                            "type": "array",
                                            "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                            "items": {
                                              "type": "number",
                                              "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                              "minimum": 0,
                                              "maximum": 255
                                            },
                                            "maxItems": 4,
                                            "minItems": 4
                                          }
                                        },
                                        "required": [
                                          "rgba"
                                        ],
                                        "additionalProperties": false
                                      },
                                      "stopFrom": {
                                        "type": "number",
                                        "description": "Where the first colour stops, 0..1.",
                                        "minimum": 0,
                                        "maximum": 1
                                      },
                                      "stopTo": {
                                        "type": "number",
                                        "description": "Where the second colour starts, 0..1.",
                                        "minimum": 0,
                                        "maximum": 1
                                      }
                                    },
                                    "required": [
                                      "style",
                                      "angle",
                                      "from",
                                      "to",
                                      "stopFrom",
                                      "stopTo"
                                    ],
                                    "additionalProperties": false
                                  }
                                },
                                "required": [
                                  "gradient"
                                ],
                                "additionalProperties": false
                              }
                            ],
                            "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
                          },
                          {
                            "type": "null"
                          }
                        ],
                        "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
                      },
                      "strokeWidth": {
                        "type": "number",
                        "description": "PERCENT; 2 means 2%, not 0.02. Of the shortest rendered edge, except a line with lineStrokeCanvas true: of canvas height, capped to the line box thickness.",
                        "minimum": 0,
                        "maximum": 100
                      },
                      "lineStrokeCanvas": {
                        "type": "boolean",
                        "description": "Line shapes only. True keeps strokeWidth a percent of canvas height, so resizing the box does not change it. False or unset is the legacy shortest-edge stroke. New editor lines use true."
                      },
                      "cornerRadius": {
                        "type": "number",
                        "description": "PERCENT of shortest rendered edge.",
                        "minimum": 0,
                        "maximum": 50
                      }
                    },
                    "required": [
                      "type",
                      "id",
                      "layer",
                      "opacity"
                    ],
                    "additionalProperties": false
                  },
                  {
                    "type": "object",
                    "description": "Native image overlay. Asset pixels and SVG path geometry remain native-owned. Source slots, SVG colour/stroke styling and the frame (corner rounding, border, fill, padding) are editable. Fill shows behind transparent pixels and around a padded image.",
                    "properties": {
                      "type": {
                        "type": "string",
                        "description": "Component type.",
                        "enum": [
                          "image"
                        ]
                      },
                      "id": {
                        "type": "string",
                        "description": "Existing saved native UID. It is not an array index or an AI-generated identity.",
                        "maxLength": 128,
                        "minLength": 8,
                        "pattern": "^[A-Za-z0-9_-]{8,128}$"
                      },
                      "layer": {
                        "type": "integer",
                        "description": "Native layer, zero is bottom. Each layer is a vertical stack, as in the editor: array order is the stack order, the first element's y is the top of the stack and each later element starts where the one above ends (its y is derived). Put elements that should overlap or sit freely in separate layers. Empty layers are removed.",
                        "minimum": 0,
                        "maximum": 14
                      },
                      "location": {
                        "type": "object",
                        "description": "Native rectangle. In % mode 0.5 is half the canvas, NOT 50; x/y range -5..5, width/height 0..5. In px mode x/y range -100000..100000, width/height 0..100000. x/y locate the rectangle; anchor does not shift its origin.",
                        "properties": {
                          "x": {
                            "type": "number",
                            "description": "Rectangle X. Bounds depend on units.",
                            "minimum": -100000,
                            "maximum": 100000
                          },
                          "y": {
                            "type": "number",
                            "description": "Rectangle Y.",
                            "minimum": -100000,
                            "maximum": 100000
                          },
                          "width": {
                            "type": "number",
                            "description": "Rectangle width; zero-size existing objects are valid.",
                            "minimum": 0,
                            "maximum": 100000
                          },
                          "height": {
                            "type": "number",
                            "description": "Rectangle height.",
                            "minimum": 0,
                            "maximum": 100000
                          },
                          "units": {
                            "type": "string",
                            "description": "Native % fractions or px. Values are not converted when changing units.",
                            "enum": [
                              "px",
                              "%"
                            ]
                          },
                          "anchor": {
                            "type": "string",
                            "description": "Text uses this for vertical placement. For images, devices and shapes this legacy field is preserved but does not position content; use position instead.",
                            "enum": [
                              "topMiddle",
                              "topLeft",
                              "topRight",
                              "middle",
                              "middleLeft",
                              "middleRight",
                              "bottomMiddle",
                              "bottomLeft",
                              "bottomRight"
                            ]
                          }
                        },
                        "required": [
                          "x",
                          "y",
                          "width",
                          "height",
                          "units",
                          "anchor"
                        ],
                        "additionalProperties": false
                      },
                      "rotation": {
                        "type": "number",
                        "description": "Rotation in degrees, not radians; perspective is a device frame variant, not arbitrary 3D.",
                        "minimum": -359,
                        "maximum": 359
                      },
                      "opacity": {
                        "type": "integer",
                        "description": "Element opacity percentage. 0 is transparent and 100 is fully opaque. AppScreens stores 100 as its native null/default, but this document always exposes the effective percentage.",
                        "minimum": 0,
                        "maximum": 100
                      },
                      "slots": {
                        "type": "array",
                        "description": "Only existing explicit source assignments. Empty slots/fallbacks are not materialized. Each field/language/target combination must remain present and unchanged; only assetId can change.",
                        "items": {
                          "type": "object",
                          "description": "One source assignment.",
                          "properties": {
                            "field": {
                              "type": "string",
                              "description": "Original storage provenance.",
                              "enum": [
                                "base",
                                "translation",
                                "legacy"
                              ]
                            },
                            "language": {
                              "type": "string",
                              "description": "An existing language or target key. It cannot create languages or targets.",
                              "maxLength": 128,
                              "minLength": 1,
                              "pattern": "^[A-Za-z0-9_-]{1,128}$"
                            },
                            "targetId": {
                              "type": "string",
                              "description": "An existing language or target key. It cannot create languages or targets.",
                              "maxLength": 128,
                              "minLength": 1,
                              "pattern": "^[A-Za-z0-9_-]{1,128}$"
                            },
                            "assetId": {
                              "type": "string",
                              "description": "Approved stable asset ID. Never a URL, data URI, signed URL or token.",
                              "maxLength": 1024,
                              "minLength": 1
                            }
                          },
                          "required": [
                            "field",
                            "language",
                            "targetId",
                            "assetId"
                          ],
                          "additionalProperties": false
                        },
                        "maxItems": 500,
                        "minItems": 0
                      },
                      "fit": {
                        "type": "string",
                        "description": "Native contain or width-cover alignment. There is no cover/fill image mode.",
                        "enum": [
                          "contain",
                          "covertop",
                          "coverbottom",
                          "covercenter"
                        ]
                      },
                      "position": {
                        "type": "string",
                        "description": "Fitted source anchor.",
                        "enum": [
                          "topMiddle",
                          "topLeft",
                          "topRight",
                          "middle",
                          "middleLeft",
                          "middleRight",
                          "bottomMiddle",
                          "bottomLeft",
                          "bottomRight"
                        ]
                      },
                      "boundary": {
                        "type": "string",
                        "description": "How rotation meets the box. inside (the default): the rotated content is scaled down until its rotated bounds fit the unrotated box, so a tilted wide image draws smaller, by min(W / (w cos a + h sin a), H / (h cos a + w sin a)) for content w x h in box W x H. outside: the box itself turns and the content keeps its size, so its corners can pass the box. Use outside to tilt a card without shrinking it.",
                        "enum": [
                          "inside",
                          "outside"
                        ]
                      },
                      "shadow": {
                        "type": "object",
                        "description": "Native relative shadow. Rendering scales offsets/blur by 0.04 times its reference size, normally full canvas height, NOT pixels. Color null with global false disables the shadow; shadow null itself resets native defaults. Inherited shadows are preserved.",
                        "properties": {
                          "color": {
                            "anyOf": [
                              {
                                "type": "object",
                                "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                "properties": {
                                  "rgba": {
                                    "type": "array",
                                    "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                    "items": {
                                      "type": "number",
                                      "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                      "minimum": 0,
                                      "maximum": 255
                                    },
                                    "maxItems": 4,
                                    "minItems": 4
                                  }
                                },
                                "required": [
                                  "rgba"
                                ],
                                "additionalProperties": false
                              },
                              {
                                "type": "null"
                              }
                            ],
                            "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA."
                          },
                          "x": {
                            "type": "number",
                            "description": "Native horizontal offset. 0.125 is 0.5% of reference size.",
                            "minimum": -0.86,
                            "maximum": 0.86
                          },
                          "y": {
                            "type": "number",
                            "description": "Native vertical offset.",
                            "minimum": -0.86,
                            "maximum": 0.86
                          },
                          "blur": {
                            "type": "number",
                            "description": "Native blur; 0.25 is 1% of reference size.",
                            "minimum": 0,
                            "maximum": 2.5
                          },
                          "global": {
                            "type": "boolean",
                            "description": "True inherits the project shadow. False uses this explicit shadow."
                          }
                        },
                        "required": [
                          "color",
                          "x",
                          "y",
                          "blur",
                          "global"
                        ],
                        "additionalProperties": false
                      },
                      "svgOverlayColor": {
                        "anyOf": [
                          {
                            "anyOf": [
                              {
                                "type": "object",
                                "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                "properties": {
                                  "rgba": {
                                    "type": "array",
                                    "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                    "items": {
                                      "type": "number",
                                      "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                      "minimum": 0,
                                      "maximum": 255
                                    },
                                    "maxItems": 4,
                                    "minItems": 4
                                  }
                                },
                                "required": [
                                  "rgba"
                                ],
                                "additionalProperties": false
                              },
                              {
                                "type": "object",
                                "description": "Gradient paint.",
                                "properties": {
                                  "gradient": {
                                    "type": "object",
                                    "description": "Two-colour gradient, as the editor's gradient picker makes it.",
                                    "properties": {
                                      "style": {
                                        "type": "string",
                                        "description": "linear, or radial from the centre point.",
                                        "enum": [
                                          "linear",
                                          "radial"
                                        ]
                                      },
                                      "angle": {
                                        "type": "number",
                                        "description": "Linear: angle in degrees. Radial: radius as a percentage (1..100), centred in the painted area.",
                                        "minimum": -360,
                                        "maximum": 360
                                      },
                                      "from": {
                                        "type": "object",
                                        "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                        "properties": {
                                          "rgba": {
                                            "type": "array",
                                            "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                            "items": {
                                              "type": "number",
                                              "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                              "minimum": 0,
                                              "maximum": 255
                                            },
                                            "maxItems": 4,
                                            "minItems": 4
                                          }
                                        },
                                        "required": [
                                          "rgba"
                                        ],
                                        "additionalProperties": false
                                      },
                                      "to": {
                                        "type": "object",
                                        "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                        "properties": {
                                          "rgba": {
                                            "type": "array",
                                            "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                            "items": {
                                              "type": "number",
                                              "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                              "minimum": 0,
                                              "maximum": 255
                                            },
                                            "maxItems": 4,
                                            "minItems": 4
                                          }
                                        },
                                        "required": [
                                          "rgba"
                                        ],
                                        "additionalProperties": false
                                      },
                                      "stopFrom": {
                                        "type": "number",
                                        "description": "Where the first colour stops, 0..1.",
                                        "minimum": 0,
                                        "maximum": 1
                                      },
                                      "stopTo": {
                                        "type": "number",
                                        "description": "Where the second colour starts, 0..1.",
                                        "minimum": 0,
                                        "maximum": 1
                                      }
                                    },
                                    "required": [
                                      "style",
                                      "angle",
                                      "from",
                                      "to",
                                      "stopFrom",
                                      "stopTo"
                                    ],
                                    "additionalProperties": false
                                  }
                                },
                                "required": [
                                  "gradient"
                                ],
                                "additionalProperties": false
                              }
                            ],
                            "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
                          },
                          {
                            "type": "null"
                          }
                        ],
                        "description": "SVG colour overlay, solid or gradient. Recolours existing visible fills and, without an explicit SVG stroke, existing strokes. Null or transparent means keep original artwork colours. No effect on raster images."
                      },
                      "svgStrokeColor": {
                        "anyOf": [
                          {
                            "anyOf": [
                              {
                                "type": "object",
                                "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                "properties": {
                                  "rgba": {
                                    "type": "array",
                                    "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                    "items": {
                                      "type": "number",
                                      "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                      "minimum": 0,
                                      "maximum": 255
                                    },
                                    "maxItems": 4,
                                    "minItems": 4
                                  }
                                },
                                "required": [
                                  "rgba"
                                ],
                                "additionalProperties": false
                              },
                              {
                                "type": "object",
                                "description": "Gradient paint.",
                                "properties": {
                                  "gradient": {
                                    "type": "object",
                                    "description": "Two-colour gradient, as the editor's gradient picker makes it.",
                                    "properties": {
                                      "style": {
                                        "type": "string",
                                        "description": "linear, or radial from the centre point.",
                                        "enum": [
                                          "linear",
                                          "radial"
                                        ]
                                      },
                                      "angle": {
                                        "type": "number",
                                        "description": "Linear: angle in degrees. Radial: radius as a percentage (1..100), centred in the painted area.",
                                        "minimum": -360,
                                        "maximum": 360
                                      },
                                      "from": {
                                        "type": "object",
                                        "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                        "properties": {
                                          "rgba": {
                                            "type": "array",
                                            "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                            "items": {
                                              "type": "number",
                                              "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                              "minimum": 0,
                                              "maximum": 255
                                            },
                                            "maxItems": 4,
                                            "minItems": 4
                                          }
                                        },
                                        "required": [
                                          "rgba"
                                        ],
                                        "additionalProperties": false
                                      },
                                      "to": {
                                        "type": "object",
                                        "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                        "properties": {
                                          "rgba": {
                                            "type": "array",
                                            "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                            "items": {
                                              "type": "number",
                                              "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                              "minimum": 0,
                                              "maximum": 255
                                            },
                                            "maxItems": 4,
                                            "minItems": 4
                                          }
                                        },
                                        "required": [
                                          "rgba"
                                        ],
                                        "additionalProperties": false
                                      },
                                      "stopFrom": {
                                        "type": "number",
                                        "description": "Where the first colour stops, 0..1.",
                                        "minimum": 0,
                                        "maximum": 1
                                      },
                                      "stopTo": {
                                        "type": "number",
                                        "description": "Where the second colour starts, 0..1.",
                                        "minimum": 0,
                                        "maximum": 1
                                      }
                                    },
                                    "required": [
                                      "style",
                                      "angle",
                                      "from",
                                      "to",
                                      "stopFrom",
                                      "stopTo"
                                    ],
                                    "additionalProperties": false
                                  }
                                },
                                "required": [
                                  "gradient"
                                ],
                                "additionalProperties": false
                              }
                            ],
                            "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
                          },
                          {
                            "type": "null"
                          }
                        ],
                        "description": "SVG path stroke, solid or gradient. Null or transparent keeps the source stroke. Uses svgStrokeWidth, not the image frame borderWidth."
                      },
                      "svgStrokeWidth": {
                        "type": "number",
                        "description": "Fraction of full canvas height, as the editor SVG stroke control: 0.01 means 1%. Needs svgStrokeColor. No effect on raster images.",
                        "minimum": 0,
                        "maximum": 0.2
                      },
                      "cornerRadius": {
                        "type": "number",
                        "description": "PERCENT of the shortest visible image edge; 50 is a circle or pill. Rounds the whole frame: fill, border and image follow it, and a padded image rounds by cornerRadius minus padding. Any frame setting clips width-cover overflow to the box.",
                        "minimum": 0,
                        "maximum": 50
                      },
                      "border": {
                        "anyOf": [
                          {
                            "anyOf": [
                              {
                                "type": "object",
                                "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                "properties": {
                                  "rgba": {
                                    "type": "array",
                                    "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                    "items": {
                                      "type": "number",
                                      "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                      "minimum": 0,
                                      "maximum": 255
                                    },
                                    "maxItems": 4,
                                    "minItems": 4
                                  }
                                },
                                "required": [
                                  "rgba"
                                ],
                                "additionalProperties": false
                              },
                              {
                                "type": "object",
                                "description": "Gradient paint.",
                                "properties": {
                                  "gradient": {
                                    "type": "object",
                                    "description": "Two-colour gradient, as the editor's gradient picker makes it.",
                                    "properties": {
                                      "style": {
                                        "type": "string",
                                        "description": "linear, or radial from the centre point.",
                                        "enum": [
                                          "linear",
                                          "radial"
                                        ]
                                      },
                                      "angle": {
                                        "type": "number",
                                        "description": "Linear: angle in degrees. Radial: radius as a percentage (1..100), centred in the painted area.",
                                        "minimum": -360,
                                        "maximum": 360
                                      },
                                      "from": {
                                        "type": "object",
                                        "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                        "properties": {
                                          "rgba": {
                                            "type": "array",
                                            "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                            "items": {
                                              "type": "number",
                                              "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                              "minimum": 0,
                                              "maximum": 255
                                            },
                                            "maxItems": 4,
                                            "minItems": 4
                                          }
                                        },
                                        "required": [
                                          "rgba"
                                        ],
                                        "additionalProperties": false
                                      },
                                      "to": {
                                        "type": "object",
                                        "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                        "properties": {
                                          "rgba": {
                                            "type": "array",
                                            "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                            "items": {
                                              "type": "number",
                                              "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                              "minimum": 0,
                                              "maximum": 255
                                            },
                                            "maxItems": 4,
                                            "minItems": 4
                                          }
                                        },
                                        "required": [
                                          "rgba"
                                        ],
                                        "additionalProperties": false
                                      },
                                      "stopFrom": {
                                        "type": "number",
                                        "description": "Where the first colour stops, 0..1.",
                                        "minimum": 0,
                                        "maximum": 1
                                      },
                                      "stopTo": {
                                        "type": "number",
                                        "description": "Where the second colour starts, 0..1.",
                                        "minimum": 0,
                                        "maximum": 1
                                      }
                                    },
                                    "required": [
                                      "style",
                                      "angle",
                                      "from",
                                      "to",
                                      "stopFrom",
                                      "stopTo"
                                    ],
                                    "additionalProperties": false
                                  }
                                },
                                "required": [
                                  "gradient"
                                ],
                                "additionalProperties": false
                              }
                            ],
                            "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
                          },
                          {
                            "type": "null"
                          }
                        ],
                        "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
                      },
                      "borderWidth": {
                        "type": "number",
                        "description": "PERCENT; 2 means 2%, not 0.02. Of the shortest visible image edge, drawn inside the image edge. Needs a border paint.",
                        "minimum": 0,
                        "maximum": 50
                      },
                      "fill": {
                        "anyOf": [
                          {
                            "anyOf": [
                              {
                                "type": "object",
                                "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                "properties": {
                                  "rgba": {
                                    "type": "array",
                                    "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                    "items": {
                                      "type": "number",
                                      "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                      "minimum": 0,
                                      "maximum": 255
                                    },
                                    "maxItems": 4,
                                    "minItems": 4
                                  }
                                },
                                "required": [
                                  "rgba"
                                ],
                                "additionalProperties": false
                              },
                              {
                                "type": "object",
                                "description": "Gradient paint.",
                                "properties": {
                                  "gradient": {
                                    "type": "object",
                                    "description": "Two-colour gradient, as the editor's gradient picker makes it.",
                                    "properties": {
                                      "style": {
                                        "type": "string",
                                        "description": "linear, or radial from the centre point.",
                                        "enum": [
                                          "linear",
                                          "radial"
                                        ]
                                      },
                                      "angle": {
                                        "type": "number",
                                        "description": "Linear: angle in degrees. Radial: radius as a percentage (1..100), centred in the painted area.",
                                        "minimum": -360,
                                        "maximum": 360
                                      },
                                      "from": {
                                        "type": "object",
                                        "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                        "properties": {
                                          "rgba": {
                                            "type": "array",
                                            "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                            "items": {
                                              "type": "number",
                                              "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                              "minimum": 0,
                                              "maximum": 255
                                            },
                                            "maxItems": 4,
                                            "minItems": 4
                                          }
                                        },
                                        "required": [
                                          "rgba"
                                        ],
                                        "additionalProperties": false
                                      },
                                      "to": {
                                        "type": "object",
                                        "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                        "properties": {
                                          "rgba": {
                                            "type": "array",
                                            "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                            "items": {
                                              "type": "number",
                                              "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                              "minimum": 0,
                                              "maximum": 255
                                            },
                                            "maxItems": 4,
                                            "minItems": 4
                                          }
                                        },
                                        "required": [
                                          "rgba"
                                        ],
                                        "additionalProperties": false
                                      },
                                      "stopFrom": {
                                        "type": "number",
                                        "description": "Where the first colour stops, 0..1.",
                                        "minimum": 0,
                                        "maximum": 1
                                      },
                                      "stopTo": {
                                        "type": "number",
                                        "description": "Where the second colour starts, 0..1.",
                                        "minimum": 0,
                                        "maximum": 1
                                      }
                                    },
                                    "required": [
                                      "style",
                                      "angle",
                                      "from",
                                      "to",
                                      "stopFrom",
                                      "stopTo"
                                    ],
                                    "additionalProperties": false
                                  }
                                },
                                "required": [
                                  "gradient"
                                ],
                                "additionalProperties": false
                              }
                            ],
                            "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
                          },
                          {
                            "type": "null"
                          }
                        ],
                        "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
                      },
                      "padding": {
                        "type": "number",
                        "description": "PERCENT of the shortest visible image edge. Insets the image inside its frame so the fill shows around it; the frame keeps its size.",
                        "minimum": 0,
                        "maximum": 40
                      }
                    },
                    "required": [
                      "type",
                      "id",
                      "layer",
                      "opacity",
                      "slots"
                    ],
                    "additionalProperties": false
                  },
                  {
                    "type": "object",
                    "description": "An unsupported native object, kept editable in AppScreens. Only layer placement/order can change in this draft; no opaque native properties are returned.",
                    "properties": {
                      "type": {
                        "type": "string",
                        "description": "Component type.",
                        "enum": [
                          "preserved"
                        ]
                      },
                      "id": {
                        "type": "string",
                        "description": "Existing saved native UID. It is not an array index or an AI-generated identity.",
                        "maxLength": 128,
                        "minLength": 8,
                        "pattern": "^[A-Za-z0-9_-]{8,128}$"
                      },
                      "layer": {
                        "type": "integer",
                        "description": "Native layer, zero is bottom. Each layer is a vertical stack, as in the editor: array order is the stack order, the first element's y is the top of the stack and each later element starts where the one above ends (its y is derived). Put elements that should overlap or sit freely in separate layers. Empty layers are removed.",
                        "minimum": 0,
                        "maximum": 14
                      }
                    },
                    "required": [
                      "type",
                      "id",
                      "layer"
                    ],
                    "additionalProperties": false
                  }
                ]
              },
              "maxItems": 100,
              "minItems": 0
            }
          },
          "required": [
            "id",
            "elements"
          ],
          "additionalProperties": false
        },
        "maxItems": 1,
        "minItems": 1
      }
    },
    "required": [
      "version",
      "screenshots"
    ],
    "additionalProperties": false
  },
  "projectSchema": {
    "type": "object",
    "description": "Editable one-page AppScreens design document. Apply against the saved baseline with current revision/hash; validate, render, inspect and use the existing export process. This is not a native scene replacement.",
    "properties": {
      "version": {
        "type": "string",
        "description": "Contract version.",
        "enum": [
          "appscreens.design.v1"
        ]
      },
      "screenshots": {
        "type": "array",
        "description": "Exactly the selected existing screenshot.",
        "items": {
          "type": "object",
          "description": "ONE existing saved screenshot. Project settings, root/global objects, languages, output targets and sibling pages are not replaceable through this document.",
          "properties": {
            "id": {
              "type": "string",
              "description": "Existing saved native UID. It is not an array index or an AI-generated identity.",
              "maxLength": 128,
              "minLength": 8,
              "pattern": "^[A-Za-z0-9_-]{8,128}$"
            },
            "background": {
              "anyOf": [
                {
                  "anyOf": [
                    {
                      "type": "object",
                      "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                      "properties": {
                        "rgba": {
                          "type": "array",
                          "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                          "items": {
                            "type": "number",
                            "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                            "minimum": 0,
                            "maximum": 255
                          },
                          "maxItems": 4,
                          "minItems": 4
                        }
                      },
                      "required": [
                        "rgba"
                      ],
                      "additionalProperties": false
                    },
                    {
                      "type": "object",
                      "description": "Gradient paint.",
                      "properties": {
                        "gradient": {
                          "type": "object",
                          "description": "Two-colour gradient, as the editor's gradient picker makes it.",
                          "properties": {
                            "style": {
                              "type": "string",
                              "description": "linear, or radial from the centre point.",
                              "enum": [
                                "linear",
                                "radial"
                              ]
                            },
                            "angle": {
                              "type": "number",
                              "description": "Linear: angle in degrees. Radial: radius as a percentage (1..100), centred in the painted area.",
                              "minimum": -360,
                              "maximum": 360
                            },
                            "from": {
                              "type": "object",
                              "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                              "properties": {
                                "rgba": {
                                  "type": "array",
                                  "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                  "items": {
                                    "type": "number",
                                    "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                    "minimum": 0,
                                    "maximum": 255
                                  },
                                  "maxItems": 4,
                                  "minItems": 4
                                }
                              },
                              "required": [
                                "rgba"
                              ],
                              "additionalProperties": false
                            },
                            "to": {
                              "type": "object",
                              "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                              "properties": {
                                "rgba": {
                                  "type": "array",
                                  "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                  "items": {
                                    "type": "number",
                                    "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                    "minimum": 0,
                                    "maximum": 255
                                  },
                                  "maxItems": 4,
                                  "minItems": 4
                                }
                              },
                              "required": [
                                "rgba"
                              ],
                              "additionalProperties": false
                            },
                            "stopFrom": {
                              "type": "number",
                              "description": "Where the first colour stops, 0..1.",
                              "minimum": 0,
                              "maximum": 1
                            },
                            "stopTo": {
                              "type": "number",
                              "description": "Where the second colour starts, 0..1.",
                              "minimum": 0,
                              "maximum": 1
                            }
                          },
                          "required": [
                            "style",
                            "angle",
                            "from",
                            "to",
                            "stopFrom",
                            "stopTo"
                          ],
                          "additionalProperties": false
                        }
                      },
                      "required": [
                        "gradient"
                      ],
                      "additionalProperties": false
                    }
                  ],
                  "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
                },
                {
                  "type": "null"
                }
              ],
              "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
            },
            "pattern": {
              "anyOf": [
                {
                  "type": "object",
                  "description": "Existing native tiled background motif. Registered library tiles remain native-only; other pattern controls are editable. This is not a positioned layer or broad landscape.",
                  "properties": {
                    "style": {
                      "type": "string",
                      "description": "Native motif mode.",
                      "enum": [
                        "dots",
                        "grid",
                        "diagonalLines",
                        "crosshatch",
                        "diamonds",
                        "waves",
                        "library"
                      ]
                    },
                    "color": {
                      "anyOf": [
                        {
                          "type": "object",
                          "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                          "properties": {
                            "rgba": {
                              "type": "array",
                              "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                              "items": {
                                "type": "number",
                                "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                "minimum": 0,
                                "maximum": 255
                              },
                              "maxItems": 4,
                              "minItems": 4
                            }
                          },
                          "required": [
                            "rgba"
                          ],
                          "additionalProperties": false
                        },
                        {
                          "type": "null"
                        }
                      ],
                      "description": "Opaque motif colour, alpha exactly 1. Do not set null: the native loader restores violet. Hide the pattern using opacity:0."
                    },
                    "opacity": {
                      "type": "number",
                      "description": "Percentage; use this, not color alpha, for transparency.",
                      "minimum": 0,
                      "maximum": 100
                    },
                    "size": {
                      "type": "number",
                      "description": "Native motif scale; motif width approx canvasWidth * .06 * size/100.",
                      "minimum": 10,
                      "maximum": 1000
                    },
                    "spacing": {
                      "type": "number",
                      "description": "Percentage of motif size.",
                      "minimum": 0,
                      "maximum": 300
                    },
                    "rotation": {
                      "type": "number",
                      "description": "Degrees.",
                      "minimum": -359,
                      "maximum": 359
                    }
                  },
                  "required": [
                    "style"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "null"
                }
              ],
              "description": "Existing native tiled background motif. Registered library tiles remain native-only; other pattern controls are editable. This is not a positioned layer or broad landscape."
            },
            "elements": {
              "type": "array",
              "description": "Existing element IDs/types only; add or remove elements with apply_project_changes. Order inside a layer follows array order.",
              "items": {
                "anyOf": [
                  {
                    "type": "object",
                    "description": "Native device frame and genuine app screenshot. Enum validity does not prove frame/appearance availability for every output target; preview and existing preflight remain mandatory.",
                    "properties": {
                      "type": {
                        "type": "string",
                        "description": "Component type.",
                        "enum": [
                          "device"
                        ]
                      },
                      "id": {
                        "type": "string",
                        "description": "Existing saved native UID. It is not an array index or an AI-generated identity.",
                        "maxLength": 128,
                        "minLength": 8,
                        "pattern": "^[A-Za-z0-9_-]{8,128}$"
                      },
                      "layer": {
                        "type": "integer",
                        "description": "Native layer, zero is bottom. Each layer is a vertical stack, as in the editor: array order is the stack order, the first element's y is the top of the stack and each later element starts where the one above ends (its y is derived). Put elements that should overlap or sit freely in separate layers. Empty layers are removed.",
                        "minimum": 0,
                        "maximum": 14
                      },
                      "location": {
                        "type": "object",
                        "description": "Native rectangle. In % mode 0.5 is half the canvas, NOT 50; x/y range -5..5, width/height 0..5. In px mode x/y range -100000..100000, width/height 0..100000. x/y locate the rectangle; anchor does not shift its origin.",
                        "properties": {
                          "x": {
                            "type": "number",
                            "description": "Rectangle X. Bounds depend on units.",
                            "minimum": -100000,
                            "maximum": 100000
                          },
                          "y": {
                            "type": "number",
                            "description": "Rectangle Y.",
                            "minimum": -100000,
                            "maximum": 100000
                          },
                          "width": {
                            "type": "number",
                            "description": "Rectangle width; zero-size existing objects are valid.",
                            "minimum": 0,
                            "maximum": 100000
                          },
                          "height": {
                            "type": "number",
                            "description": "Rectangle height.",
                            "minimum": 0,
                            "maximum": 100000
                          },
                          "units": {
                            "type": "string",
                            "description": "Native % fractions or px. Values are not converted when changing units.",
                            "enum": [
                              "px",
                              "%"
                            ]
                          },
                          "anchor": {
                            "type": "string",
                            "description": "Text uses this for vertical placement. For images, devices and shapes this legacy field is preserved but does not position content; use position instead.",
                            "enum": [
                              "topMiddle",
                              "topLeft",
                              "topRight",
                              "middle",
                              "middleLeft",
                              "middleRight",
                              "bottomMiddle",
                              "bottomLeft",
                              "bottomRight"
                            ]
                          }
                        },
                        "required": [
                          "x",
                          "y",
                          "width",
                          "height",
                          "units",
                          "anchor"
                        ],
                        "additionalProperties": false
                      },
                      "rotation": {
                        "type": "number",
                        "description": "Rotation in degrees, not radians; perspective is a device frame variant, not arbitrary 3D.",
                        "minimum": -359,
                        "maximum": 359
                      },
                      "opacity": {
                        "type": "integer",
                        "description": "Element opacity percentage. 0 is transparent and 100 is fully opaque. AppScreens stores 100 as its native null/default, but this document always exposes the effective percentage.",
                        "minimum": 0,
                        "maximum": 100
                      },
                      "slots": {
                        "type": "array",
                        "description": "Only existing explicit source assignments. Empty slots/fallbacks are not materialized. Each field/language/target combination must remain present and unchanged; only assetId can change.",
                        "items": {
                          "type": "object",
                          "description": "One source assignment.",
                          "properties": {
                            "field": {
                              "type": "string",
                              "description": "Original storage provenance.",
                              "enum": [
                                "base",
                                "translation",
                                "legacy"
                              ]
                            },
                            "language": {
                              "type": "string",
                              "description": "An existing language or target key. It cannot create languages or targets.",
                              "maxLength": 128,
                              "minLength": 1,
                              "pattern": "^[A-Za-z0-9_-]{1,128}$"
                            },
                            "targetId": {
                              "type": "string",
                              "description": "An existing language or target key. It cannot create languages or targets.",
                              "maxLength": 128,
                              "minLength": 1,
                              "pattern": "^[A-Za-z0-9_-]{1,128}$"
                            },
                            "assetId": {
                              "type": "string",
                              "description": "Approved stable asset ID. Never a URL, data URI, signed URL or token.",
                              "maxLength": 1024,
                              "minLength": 1
                            }
                          },
                          "required": [
                            "field",
                            "language",
                            "targetId",
                            "assetId"
                          ],
                          "additionalProperties": false
                        },
                        "maxItems": 500,
                        "minItems": 0
                      },
                      "fit": {
                        "type": "string",
                        "description": "Native contain or width-cover alignment. There is no cover/fill image mode.",
                        "enum": [
                          "contain",
                          "covertop",
                          "coverbottom",
                          "covercenter"
                        ]
                      },
                      "position": {
                        "type": "string",
                        "description": "Fitted source anchor.",
                        "enum": [
                          "topMiddle",
                          "topLeft",
                          "topRight",
                          "middle",
                          "middleLeft",
                          "middleRight",
                          "bottomMiddle",
                          "bottomLeft",
                          "bottomRight"
                        ]
                      },
                      "boundary": {
                        "type": "string",
                        "description": "How rotation meets the box. inside (the default): the rotated content is scaled down until its rotated bounds fit the unrotated box, so a tilted wide image draws smaller, by min(W / (w cos a + h sin a), H / (h cos a + w sin a)) for content w x h in box W x H. outside: the box itself turns and the content keeps its size, so its corners can pass the box. Use outside to tilt a card without shrinking it.",
                        "enum": [
                          "inside",
                          "outside"
                        ]
                      },
                      "shadow": {
                        "type": "object",
                        "description": "Native relative shadow. Rendering scales offsets/blur by 0.04 times its reference size, normally full canvas height, NOT pixels. Color null with global false disables the shadow; shadow null itself resets native defaults. Inherited shadows are preserved.",
                        "properties": {
                          "color": {
                            "anyOf": [
                              {
                                "type": "object",
                                "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                "properties": {
                                  "rgba": {
                                    "type": "array",
                                    "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                    "items": {
                                      "type": "number",
                                      "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                      "minimum": 0,
                                      "maximum": 255
                                    },
                                    "maxItems": 4,
                                    "minItems": 4
                                  }
                                },
                                "required": [
                                  "rgba"
                                ],
                                "additionalProperties": false
                              },
                              {
                                "type": "null"
                              }
                            ],
                            "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA."
                          },
                          "x": {
                            "type": "number",
                            "description": "Native horizontal offset. 0.125 is 0.5% of reference size.",
                            "minimum": -0.86,
                            "maximum": 0.86
                          },
                          "y": {
                            "type": "number",
                            "description": "Native vertical offset.",
                            "minimum": -0.86,
                            "maximum": 0.86
                          },
                          "blur": {
                            "type": "number",
                            "description": "Native blur; 0.25 is 1% of reference size.",
                            "minimum": 0,
                            "maximum": 2.5
                          },
                          "global": {
                            "type": "boolean",
                            "description": "True inherits the project shadow. False uses this explicit shadow."
                          }
                        },
                        "required": [
                          "color",
                          "x",
                          "y",
                          "blur",
                          "global"
                        ],
                        "additionalProperties": false
                      },
                      "frame": {
                        "type": "string",
                        "description": "Existing frame variants. Perspective variants are asset-defined, not arbitrary XYZ rotation.",
                        "enum": [
                          "full",
                          "dynamic",
                          "none",
                          "cover",
                          "warpleft",
                          "warpright",
                          "nonewarpleft",
                          "nonewarpright"
                        ]
                      },
                      "appearance": {
                        "type": "string",
                        "description": "Native appearance. Availability depends on the output target; inspect a rendered preview. Missing frame artwork uses the renderer fallback.",
                        "enum": [
                          "black",
                          "reallight",
                          "realgold",
                          "light",
                          "dark",
                          "granite",
                          "silver",
                          "mint",
                          "apple",
                          "earth",
                          "green",
                          "rose",
                          "strawberry",
                          "bluelagoon",
                          "space",
                          "berry",
                          "lemon",
                          "gold",
                          "coral"
                        ]
                      },
                      "orientation": {
                        "type": "string",
                        "description": "Device orientation.",
                        "enum": [
                          "portrait",
                          "landscapeleft",
                          "landscaperight"
                        ]
                      },
                      "blankWhenEmpty": {
                        "type": "boolean",
                        "description": "Show a plain dark screen when no app capture is available. False or unset shows the sample screenshot. Assigned captures take precedence. No asset is created or assigned by this setting."
                      },
                      "rounding": {
                        "anyOf": [
                          {
                            "type": "number",
                            "description": "Corner rounding, as in the editor: null is Auto (the frame's own screen corners) and 0 is None. Only dynamic and frameless variants use it.",
                            "minimum": 0,
                            "maximum": 0
                          },
                          {
                            "type": "null"
                          }
                        ],
                        "description": "Corner rounding, as in the editor: null is Auto (the frame's own screen corners) and 0 is None. Only dynamic and frameless variants use it."
                      },
                      "dynamicFrameColor": {
                        "anyOf": [
                          {
                            "type": "object",
                            "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                            "properties": {
                              "rgba": {
                                "type": "array",
                                "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                "items": {
                                  "type": "number",
                                  "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                  "minimum": 0,
                                  "maximum": 255
                                },
                                "maxItems": 4,
                                "minItems": 4
                              }
                            },
                            "required": [
                              "rgba"
                            ],
                            "additionalProperties": false
                          },
                          {
                            "type": "null"
                          }
                        ],
                        "description": "Visible solid dynamic frame colour. Changed null/alpha-zero would reset its native default and is rejected."
                      },
                      "dynamicFrameSize": {
                        "type": "number",
                        "description": "Fraction of shortest screenshot edge, 0..5%. Only dynamic frames use this.",
                        "minimum": 0,
                        "maximum": 0.05
                      },
                      "dynamicPadding": {
                        "type": "number",
                        "description": "Fraction of shortest screenshot edge, 0..5%. Only dynamic frames use this.",
                        "minimum": 0,
                        "maximum": 0.05
                      },
                      "dynamicPaddingColor": {
                        "anyOf": [
                          {
                            "type": "object",
                            "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                            "properties": {
                              "rgba": {
                                "type": "array",
                                "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                "items": {
                                  "type": "number",
                                  "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                  "minimum": 0,
                                  "maximum": 255
                                },
                                "maxItems": 4,
                                "minItems": 4
                              }
                            },
                            "required": [
                              "rgba"
                            ],
                            "additionalProperties": false
                          },
                          {
                            "type": "null"
                          }
                        ],
                        "description": "Solid dynamic padding colour, including alpha zero for transparent padding. Null restores the native default white at 20% opacity."
                      },
                      "dynamicInfill": {
                        "anyOf": [
                          {
                            "type": "object",
                            "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                            "properties": {
                              "rgba": {
                                "type": "array",
                                "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                "items": {
                                  "type": "number",
                                  "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                  "minimum": 0,
                                  "maximum": 255
                                },
                                "maxItems": 4,
                                "minItems": 4
                              }
                            },
                            "required": [
                              "rgba"
                            ],
                            "additionalProperties": false
                          },
                          {
                            "type": "null"
                          }
                        ],
                        "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA."
                      },
                      "displayDevices": {
                        "type": "array",
                        "description": "Overrides the project display for this frame on a selected output size. Use set_project_settings with patch.targets.targetOverrides for a display shared across the set. Set a layer override only when requested or when this frame needs a different device, such as a watch on a phone page. A \"global\" entry is this layer's fallback when it has no override for the output size. Preserve the list on unrelated edits. Send an empty list only to clear all overrides for this layer.",
                        "items": {
                          "type": "object",
                          "description": "One mapping.",
                          "properties": {
                            "targetId": {
                              "type": "string",
                              "description": "An existing language or target key. It cannot create languages or targets.",
                              "maxLength": 128,
                              "minLength": 1,
                              "pattern": "^[A-Za-z0-9_-]{1,128}$"
                            },
                            "displayDevice": {
                              "type": "string",
                              "description": "An existing language or target key. It cannot create languages or targets.",
                              "maxLength": 128,
                              "minLength": 1,
                              "pattern": "^[A-Za-z0-9_-]{1,128}$"
                            }
                          },
                          "required": [
                            "targetId",
                            "displayDevice"
                          ],
                          "additionalProperties": false
                        },
                        "maxItems": 100,
                        "minItems": 0
                      }
                    },
                    "required": [
                      "type",
                      "id",
                      "layer",
                      "opacity",
                      "slots"
                    ],
                    "additionalProperties": false
                  },
                  {
                    "type": "object",
                    "description": "Existing title/subtitle group. Common element shadow is not rendered on glyphs, so only title/subtitle block shadow is editable. Translation overrides/inactive locales stay native-only in this draft; use existing text tools for localization.",
                    "properties": {
                      "type": {
                        "type": "string",
                        "description": "Component type.",
                        "enum": [
                          "text"
                        ]
                      },
                      "id": {
                        "type": "string",
                        "description": "Existing saved native UID. It is not an array index or an AI-generated identity.",
                        "maxLength": 128,
                        "minLength": 8,
                        "pattern": "^[A-Za-z0-9_-]{8,128}$"
                      },
                      "layer": {
                        "type": "integer",
                        "description": "Native layer, zero is bottom. Each layer is a vertical stack, as in the editor: array order is the stack order, the first element's y is the top of the stack and each later element starts where the one above ends (its y is derived). Put elements that should overlap or sit freely in separate layers. Empty layers are removed.",
                        "minimum": 0,
                        "maximum": 14
                      },
                      "location": {
                        "type": "object",
                        "description": "Native rectangle. In % mode 0.5 is half the canvas, NOT 50; x/y range -5..5, width/height 0..5. In px mode x/y range -100000..100000, width/height 0..100000. x/y locate the rectangle; anchor does not shift its origin.",
                        "properties": {
                          "x": {
                            "type": "number",
                            "description": "Rectangle X. Bounds depend on units.",
                            "minimum": -100000,
                            "maximum": 100000
                          },
                          "y": {
                            "type": "number",
                            "description": "Rectangle Y.",
                            "minimum": -100000,
                            "maximum": 100000
                          },
                          "width": {
                            "type": "number",
                            "description": "Rectangle width; zero-size existing objects are valid.",
                            "minimum": 0,
                            "maximum": 100000
                          },
                          "height": {
                            "type": "number",
                            "description": "Rectangle height.",
                            "minimum": 0,
                            "maximum": 100000
                          },
                          "units": {
                            "type": "string",
                            "description": "Native % fractions or px. Values are not converted when changing units.",
                            "enum": [
                              "px",
                              "%"
                            ]
                          },
                          "anchor": {
                            "type": "string",
                            "description": "Vertical text placement: topMiddle, middle or bottomMiddle. Horizontal text alignment belongs to title.align/subtitle.align. Older side anchors are accepted and normalised to the corresponding vertical position.",
                            "enum": [
                              "topMiddle",
                              "middle",
                              "bottomMiddle"
                            ]
                          }
                        },
                        "required": [
                          "x",
                          "y",
                          "width",
                          "height",
                          "units",
                          "anchor"
                        ],
                        "additionalProperties": false
                      },
                      "rotation": {
                        "type": "number",
                        "description": "Rotation in degrees, not radians; perspective is a device frame variant, not arbitrary 3D.",
                        "minimum": -359,
                        "maximum": 359
                      },
                      "opacity": {
                        "type": "integer",
                        "description": "Element opacity percentage. 0 is transparent and 100 is fully opaque. AppScreens stores 100 as its native null/default, but this document always exposes the effective percentage.",
                        "minimum": 0,
                        "maximum": 100
                      },
                      "title": {
                        "type": "object",
                        "description": "Existing native title/subtitle block. Only exported properties are editable. Native inline gradient/highlight and unsupported ops remain unchanged. Fonts are names from the page or list_fonts, without source URLs.",
                        "properties": {
                          "runs": {
                            "type": "array",
                            "description": "Existing rich runs, same number/order; text, bold/italic/underline and colour can change.",
                            "items": {
                              "type": "object",
                              "description": "Literal native text run, including intentional newlines. Existing run count/order stays fixed so unrepresented inline formatting is preserved. No HTML, embeds, Quill commands or automatic terminal newline conversion.",
                              "properties": {
                                "text": {
                                  "type": "string",
                                  "description": "Literal Unicode text, never HTML. A title or subtitle has at most 250 characters across all runs, excluding its final Quill newline.",
                                  "maxLength": 251
                                },
                                "bold": {
                                  "type": "boolean",
                                  "description": "Inline bold."
                                },
                                "italic": {
                                  "type": "boolean",
                                  "description": "Inline italic."
                                },
                                "underline": {
                                  "type": "boolean",
                                  "description": "Inline underline."
                                },
                                "color": {
                                  "anyOf": [
                                    {
                                      "type": "object",
                                      "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                      "properties": {
                                        "rgba": {
                                          "type": "array",
                                          "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                          "items": {
                                            "type": "number",
                                            "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                            "minimum": 0,
                                            "maximum": 255
                                          },
                                          "maxItems": 4,
                                          "minItems": 4
                                        }
                                      },
                                      "required": [
                                        "rgba"
                                      ],
                                      "additionalProperties": false
                                    },
                                    {
                                      "type": "null"
                                    }
                                  ],
                                  "description": "Inline solid colour of this run; null uses the block colour. Omitted when the run has a gradient or other native paint, which stays unchanged."
                                }
                              },
                              "required": [
                                "text",
                                "bold",
                                "italic",
                                "underline"
                              ],
                              "additionalProperties": false
                            },
                            "maxItems": 500,
                            "minItems": 0
                          },
                          "font": {
                            "type": "string",
                            "description": "Font family name: one already on the page, or a Google or account font from list_fonts. Never a font URL. Text with global true follows the project font and can't take its own, as in the editor: send global: false with the font.",
                            "maxLength": 200
                          },
                          "global": {
                            "type": "boolean",
                            "description": "Follow the project's title or subtitle font (set in project settings). When true, font is this text's own font, used again if global is turned off."
                          },
                          "maxFontSize": {
                            "type": "number",
                            "description": "Fraction of full canvas width. Effective only when fontSizeLock is false, which takes the block out of the matched set size. May be supplied when a locked baseline omitted this native setting.",
                            "minimum": 0.005,
                            "maximum": 1
                          },
                          "fontSizeLock": {
                            "type": "boolean",
                            "description": "Match text size (recommended, the template default): true gives every matched caption the size of the smallest one that fits, per language and output size, so the set stays consistent. False enables maxFontSize for this block only."
                          },
                          "multiline": {
                            "type": "boolean",
                            "description": "Allow native multiline layout."
                          },
                          "align": {
                            "type": "string",
                            "description": "Block alignment, not an inline operation.",
                            "enum": [
                              "left",
                              "right",
                              "center"
                            ]
                          },
                          "color": {
                            "anyOf": [
                              {
                                "type": "object",
                                "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                "properties": {
                                  "rgba": {
                                    "type": "array",
                                    "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                    "items": {
                                      "type": "number",
                                      "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                      "minimum": 0,
                                      "maximum": 255
                                    },
                                    "maxItems": 4,
                                    "minItems": 4
                                  }
                                },
                                "required": [
                                  "rgba"
                                ],
                                "additionalProperties": false
                              },
                              {
                                "type": "null"
                              }
                            ],
                            "description": "Opaque or visible solid text colour. Changed null/alpha-zero is rejected because native serialization restores its default instead of preserving transparency."
                          },
                          "lineHeight": {
                            "type": "number",
                            "description": "Native line-height multiplier.",
                            "minimum": 0.01,
                            "maximum": 3
                          },
                          "letterSpacing": {
                            "type": "number",
                            "description": "Native fraction of font size, not pixels.",
                            "minimum": 0,
                            "maximum": 0.25
                          },
                          "highlightPaddingX": {
                            "type": "number",
                            "description": "Fraction of font size.",
                            "minimum": 0,
                            "maximum": 1
                          },
                          "highlightPaddingY": {
                            "anyOf": [
                              {
                                "type": "number",
                                "description": "Fraction of font size. Null inherits X.",
                                "minimum": 0,
                                "maximum": 1
                              },
                              {
                                "type": "null"
                              }
                            ],
                            "description": "Fraction of font size. Null inherits X."
                          },
                          "highlightRounding": {
                            "type": "number",
                            "description": "Fraction of highlight height.",
                            "minimum": 0,
                            "maximum": 0.5
                          },
                          "shadow": {
                            "type": "object",
                            "description": "Native relative shadow. Rendering scales offsets/blur by 0.04 times its reference size, normally full canvas height, NOT pixels. Color null with global false disables the shadow; shadow null itself resets native defaults. Inherited shadows are preserved.",
                            "properties": {
                              "color": {
                                "anyOf": [
                                  {
                                    "type": "object",
                                    "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                    "properties": {
                                      "rgba": {
                                        "type": "array",
                                        "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                        "items": {
                                          "type": "number",
                                          "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                          "minimum": 0,
                                          "maximum": 255
                                        },
                                        "maxItems": 4,
                                        "minItems": 4
                                      }
                                    },
                                    "required": [
                                      "rgba"
                                    ],
                                    "additionalProperties": false
                                  },
                                  {
                                    "type": "null"
                                  }
                                ],
                                "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA."
                              },
                              "x": {
                                "type": "number",
                                "description": "Native horizontal offset. 0.125 is 0.5% of reference size.",
                                "minimum": -0.86,
                                "maximum": 0.86
                              },
                              "y": {
                                "type": "number",
                                "description": "Native vertical offset.",
                                "minimum": -0.86,
                                "maximum": 0.86
                              },
                              "blur": {
                                "type": "number",
                                "description": "Native blur; 0.25 is 1% of reference size.",
                                "minimum": 0,
                                "maximum": 2.5
                              },
                              "global": {
                                "type": "boolean",
                                "description": "True inherits the project shadow. False uses this explicit shadow."
                              }
                            },
                            "required": [
                              "color",
                              "x",
                              "y",
                              "blur",
                              "global"
                            ],
                            "additionalProperties": false
                          }
                        },
                        "required": [],
                        "additionalProperties": false
                      },
                      "subtitle": {
                        "anyOf": [
                          {
                            "type": "object",
                            "description": "Existing native title/subtitle block. Only exported properties are editable. Native inline gradient/highlight and unsupported ops remain unchanged. Fonts are names from the page or list_fonts, without source URLs.",
                            "properties": {
                              "runs": {
                                "type": "array",
                                "description": "Existing rich runs, same number/order; text, bold/italic/underline and colour can change.",
                                "items": {
                                  "type": "object",
                                  "description": "Literal native text run, including intentional newlines. Existing run count/order stays fixed so unrepresented inline formatting is preserved. No HTML, embeds, Quill commands or automatic terminal newline conversion.",
                                  "properties": {
                                    "text": {
                                      "type": "string",
                                      "description": "Literal Unicode text, never HTML. A title or subtitle has at most 250 characters across all runs, excluding its final Quill newline.",
                                      "maxLength": 251
                                    },
                                    "bold": {
                                      "type": "boolean",
                                      "description": "Inline bold."
                                    },
                                    "italic": {
                                      "type": "boolean",
                                      "description": "Inline italic."
                                    },
                                    "underline": {
                                      "type": "boolean",
                                      "description": "Inline underline."
                                    },
                                    "color": {
                                      "anyOf": [
                                        {
                                          "type": "object",
                                          "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                          "properties": {
                                            "rgba": {
                                              "type": "array",
                                              "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                              "items": {
                                                "type": "number",
                                                "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                                "minimum": 0,
                                                "maximum": 255
                                              },
                                              "maxItems": 4,
                                              "minItems": 4
                                            }
                                          },
                                          "required": [
                                            "rgba"
                                          ],
                                          "additionalProperties": false
                                        },
                                        {
                                          "type": "null"
                                        }
                                      ],
                                      "description": "Inline solid colour of this run; null uses the block colour. Omitted when the run has a gradient or other native paint, which stays unchanged."
                                    }
                                  },
                                  "required": [
                                    "text",
                                    "bold",
                                    "italic",
                                    "underline"
                                  ],
                                  "additionalProperties": false
                                },
                                "maxItems": 500,
                                "minItems": 0
                              },
                              "font": {
                                "type": "string",
                                "description": "Font family name: one already on the page, or a Google or account font from list_fonts. Never a font URL. Text with global true follows the project font and can't take its own, as in the editor: send global: false with the font.",
                                "maxLength": 200
                              },
                              "global": {
                                "type": "boolean",
                                "description": "Follow the project's title or subtitle font (set in project settings). When true, font is this text's own font, used again if global is turned off."
                              },
                              "maxFontSize": {
                                "type": "number",
                                "description": "Fraction of full canvas width. Effective only when fontSizeLock is false, which takes the block out of the matched set size. May be supplied when a locked baseline omitted this native setting.",
                                "minimum": 0.005,
                                "maximum": 1
                              },
                              "fontSizeLock": {
                                "type": "boolean",
                                "description": "Match text size (recommended, the template default): true gives every matched caption the size of the smallest one that fits, per language and output size, so the set stays consistent. False enables maxFontSize for this block only."
                              },
                              "multiline": {
                                "type": "boolean",
                                "description": "Allow native multiline layout."
                              },
                              "align": {
                                "type": "string",
                                "description": "Block alignment, not an inline operation.",
                                "enum": [
                                  "left",
                                  "right",
                                  "center"
                                ]
                              },
                              "color": {
                                "anyOf": [
                                  {
                                    "type": "object",
                                    "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                    "properties": {
                                      "rgba": {
                                        "type": "array",
                                        "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                        "items": {
                                          "type": "number",
                                          "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                          "minimum": 0,
                                          "maximum": 255
                                        },
                                        "maxItems": 4,
                                        "minItems": 4
                                      }
                                    },
                                    "required": [
                                      "rgba"
                                    ],
                                    "additionalProperties": false
                                  },
                                  {
                                    "type": "null"
                                  }
                                ],
                                "description": "Opaque or visible solid text colour. Changed null/alpha-zero is rejected because native serialization restores its default instead of preserving transparency."
                              },
                              "lineHeight": {
                                "type": "number",
                                "description": "Native line-height multiplier.",
                                "minimum": 0.01,
                                "maximum": 3
                              },
                              "letterSpacing": {
                                "type": "number",
                                "description": "Native fraction of font size, not pixels.",
                                "minimum": 0,
                                "maximum": 0.25
                              },
                              "highlightPaddingX": {
                                "type": "number",
                                "description": "Fraction of font size.",
                                "minimum": 0,
                                "maximum": 1
                              },
                              "highlightPaddingY": {
                                "anyOf": [
                                  {
                                    "type": "number",
                                    "description": "Fraction of font size. Null inherits X.",
                                    "minimum": 0,
                                    "maximum": 1
                                  },
                                  {
                                    "type": "null"
                                  }
                                ],
                                "description": "Fraction of font size. Null inherits X."
                              },
                              "highlightRounding": {
                                "type": "number",
                                "description": "Fraction of highlight height.",
                                "minimum": 0,
                                "maximum": 0.5
                              },
                              "shadow": {
                                "type": "object",
                                "description": "Native relative shadow. Rendering scales offsets/blur by 0.04 times its reference size, normally full canvas height, NOT pixels. Color null with global false disables the shadow; shadow null itself resets native defaults. Inherited shadows are preserved.",
                                "properties": {
                                  "color": {
                                    "anyOf": [
                                      {
                                        "type": "object",
                                        "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                        "properties": {
                                          "rgba": {
                                            "type": "array",
                                            "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                            "items": {
                                              "type": "number",
                                              "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                              "minimum": 0,
                                              "maximum": 255
                                            },
                                            "maxItems": 4,
                                            "minItems": 4
                                          }
                                        },
                                        "required": [
                                          "rgba"
                                        ],
                                        "additionalProperties": false
                                      },
                                      {
                                        "type": "null"
                                      }
                                    ],
                                    "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA."
                                  },
                                  "x": {
                                    "type": "number",
                                    "description": "Native horizontal offset. 0.125 is 0.5% of reference size.",
                                    "minimum": -0.86,
                                    "maximum": 0.86
                                  },
                                  "y": {
                                    "type": "number",
                                    "description": "Native vertical offset.",
                                    "minimum": -0.86,
                                    "maximum": 0.86
                                  },
                                  "blur": {
                                    "type": "number",
                                    "description": "Native blur; 0.25 is 1% of reference size.",
                                    "minimum": 0,
                                    "maximum": 2.5
                                  },
                                  "global": {
                                    "type": "boolean",
                                    "description": "True inherits the project shadow. False uses this explicit shadow."
                                  }
                                },
                                "required": [
                                  "color",
                                  "x",
                                  "y",
                                  "blur",
                                  "global"
                                ],
                                "additionalProperties": false
                              }
                            },
                            "required": [],
                            "additionalProperties": false
                          },
                          {
                            "type": "null"
                          }
                        ],
                        "description": "Existing native title/subtitle block. Only exported properties are editable. Native inline gradient/highlight and unsupported ops remain unchanged. Fonts are names from the page or list_fonts, without source URLs."
                      },
                      "spacing": {
                        "type": "number",
                        "description": "Gap as fraction of fitted title/subtitle group height.",
                        "minimum": 0,
                        "maximum": 1
                      },
                      "titleRatio": {
                        "type": "number",
                        "description": "Title share of group height; at most 0.99 with a subtitle, 1 is valid without a subtitle.",
                        "minimum": 0,
                        "maximum": 1
                      },
                      "decoration": {
                        "type": "string",
                        "description": "The editor's text decoration. Use laurels for award captions, geometric styles for labels and speech bubbles for quotes. Start with laurelCompactTight for a short award caption. Choose a wider compact style if the caption needs more room. Use none to clear the decoration. Use only verified award and rating claims.",
                        "enum": [
                          "none",
                          "laurelCompactSquare",
                          "laurelCompactTight",
                          "laurelCompactWide",
                          "laurelCompactWider",
                          "laurelTight",
                          "laurelWide",
                          "laurelWider",
                          "rectangle",
                          "rectangleRounded",
                          "ovalRounded",
                          "square",
                          "squareRounded",
                          "circle",
                          "badge",
                          "commentLeft",
                          "commentRight",
                          "chatBubbleLeft",
                          "chatBubbleRight",
                          "starBackground"
                        ]
                      },
                      "decorationFill": {
                        "anyOf": [
                          {
                            "anyOf": [
                              {
                                "type": "object",
                                "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                "properties": {
                                  "rgba": {
                                    "type": "array",
                                    "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                    "items": {
                                      "type": "number",
                                      "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                      "minimum": 0,
                                      "maximum": 255
                                    },
                                    "maxItems": 4,
                                    "minItems": 4
                                  }
                                },
                                "required": [
                                  "rgba"
                                ],
                                "additionalProperties": false
                              },
                              {
                                "type": "object",
                                "description": "Gradient paint.",
                                "properties": {
                                  "gradient": {
                                    "type": "object",
                                    "description": "Two-colour gradient, as the editor's gradient picker makes it.",
                                    "properties": {
                                      "style": {
                                        "type": "string",
                                        "description": "linear, or radial from the centre point.",
                                        "enum": [
                                          "linear",
                                          "radial"
                                        ]
                                      },
                                      "angle": {
                                        "type": "number",
                                        "description": "Linear: angle in degrees. Radial: radius as a percentage (1..100), centred in the painted area.",
                                        "minimum": -360,
                                        "maximum": 360
                                      },
                                      "from": {
                                        "type": "object",
                                        "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                        "properties": {
                                          "rgba": {
                                            "type": "array",
                                            "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                            "items": {
                                              "type": "number",
                                              "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                              "minimum": 0,
                                              "maximum": 255
                                            },
                                            "maxItems": 4,
                                            "minItems": 4
                                          }
                                        },
                                        "required": [
                                          "rgba"
                                        ],
                                        "additionalProperties": false
                                      },
                                      "to": {
                                        "type": "object",
                                        "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                        "properties": {
                                          "rgba": {
                                            "type": "array",
                                            "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                            "items": {
                                              "type": "number",
                                              "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                              "minimum": 0,
                                              "maximum": 255
                                            },
                                            "maxItems": 4,
                                            "minItems": 4
                                          }
                                        },
                                        "required": [
                                          "rgba"
                                        ],
                                        "additionalProperties": false
                                      },
                                      "stopFrom": {
                                        "type": "number",
                                        "description": "Where the first colour stops, 0..1.",
                                        "minimum": 0,
                                        "maximum": 1
                                      },
                                      "stopTo": {
                                        "type": "number",
                                        "description": "Where the second colour starts, 0..1.",
                                        "minimum": 0,
                                        "maximum": 1
                                      }
                                    },
                                    "required": [
                                      "style",
                                      "angle",
                                      "from",
                                      "to",
                                      "stopFrom",
                                      "stopTo"
                                    ],
                                    "additionalProperties": false
                                  }
                                },
                                "required": [
                                  "gradient"
                                ],
                                "additionalProperties": false
                              }
                            ],
                            "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
                          },
                          {
                            "type": "null"
                          }
                        ],
                        "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
                      },
                      "decorationStroke": {
                        "anyOf": [
                          {
                            "anyOf": [
                              {
                                "type": "object",
                                "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                "properties": {
                                  "rgba": {
                                    "type": "array",
                                    "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                    "items": {
                                      "type": "number",
                                      "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                      "minimum": 0,
                                      "maximum": 255
                                    },
                                    "maxItems": 4,
                                    "minItems": 4
                                  }
                                },
                                "required": [
                                  "rgba"
                                ],
                                "additionalProperties": false
                              },
                              {
                                "type": "object",
                                "description": "Gradient paint.",
                                "properties": {
                                  "gradient": {
                                    "type": "object",
                                    "description": "Two-colour gradient, as the editor's gradient picker makes it.",
                                    "properties": {
                                      "style": {
                                        "type": "string",
                                        "description": "linear, or radial from the centre point.",
                                        "enum": [
                                          "linear",
                                          "radial"
                                        ]
                                      },
                                      "angle": {
                                        "type": "number",
                                        "description": "Linear: angle in degrees. Radial: radius as a percentage (1..100), centred in the painted area.",
                                        "minimum": -360,
                                        "maximum": 360
                                      },
                                      "from": {
                                        "type": "object",
                                        "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                        "properties": {
                                          "rgba": {
                                            "type": "array",
                                            "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                            "items": {
                                              "type": "number",
                                              "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                              "minimum": 0,
                                              "maximum": 255
                                            },
                                            "maxItems": 4,
                                            "minItems": 4
                                          }
                                        },
                                        "required": [
                                          "rgba"
                                        ],
                                        "additionalProperties": false
                                      },
                                      "to": {
                                        "type": "object",
                                        "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                        "properties": {
                                          "rgba": {
                                            "type": "array",
                                            "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                            "items": {
                                              "type": "number",
                                              "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                              "minimum": 0,
                                              "maximum": 255
                                            },
                                            "maxItems": 4,
                                            "minItems": 4
                                          }
                                        },
                                        "required": [
                                          "rgba"
                                        ],
                                        "additionalProperties": false
                                      },
                                      "stopFrom": {
                                        "type": "number",
                                        "description": "Where the first colour stops, 0..1.",
                                        "minimum": 0,
                                        "maximum": 1
                                      },
                                      "stopTo": {
                                        "type": "number",
                                        "description": "Where the second colour starts, 0..1.",
                                        "minimum": 0,
                                        "maximum": 1
                                      }
                                    },
                                    "required": [
                                      "style",
                                      "angle",
                                      "from",
                                      "to",
                                      "stopFrom",
                                      "stopTo"
                                    ],
                                    "additionalProperties": false
                                  }
                                },
                                "required": [
                                  "gradient"
                                ],
                                "additionalProperties": false
                              }
                            ],
                            "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
                          },
                          {
                            "type": "null"
                          }
                        ],
                        "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
                      },
                      "decorationStrokeWidth": {
                        "type": "number",
                        "description": "Fraction of decoration image height, not pixels. 0.01 is 1%.",
                        "minimum": 0,
                        "maximum": 0.2
                      },
                      "decorationShadow": {
                        "type": "object",
                        "description": "Native relative shadow. Rendering scales offsets/blur by 0.04 times its reference size, normally full canvas height, NOT pixels. Color null with global false disables the shadow; shadow null itself resets native defaults. Inherited shadows are preserved.",
                        "properties": {
                          "color": {
                            "anyOf": [
                              {
                                "type": "object",
                                "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                "properties": {
                                  "rgba": {
                                    "type": "array",
                                    "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                    "items": {
                                      "type": "number",
                                      "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                      "minimum": 0,
                                      "maximum": 255
                                    },
                                    "maxItems": 4,
                                    "minItems": 4
                                  }
                                },
                                "required": [
                                  "rgba"
                                ],
                                "additionalProperties": false
                              },
                              {
                                "type": "null"
                              }
                            ],
                            "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA."
                          },
                          "x": {
                            "type": "number",
                            "description": "Native horizontal offset. 0.125 is 0.5% of reference size.",
                            "minimum": -0.86,
                            "maximum": 0.86
                          },
                          "y": {
                            "type": "number",
                            "description": "Native vertical offset.",
                            "minimum": -0.86,
                            "maximum": 0.86
                          },
                          "blur": {
                            "type": "number",
                            "description": "Native blur; 0.25 is 1% of reference size.",
                            "minimum": 0,
                            "maximum": 2.5
                          },
                          "global": {
                            "type": "boolean",
                            "description": "True inherits the project shadow. False uses this explicit shadow."
                          }
                        },
                        "required": [
                          "color",
                          "x",
                          "y",
                          "blur",
                          "global"
                        ],
                        "additionalProperties": false
                      }
                    },
                    "required": [
                      "type",
                      "id",
                      "layer",
                      "opacity"
                    ],
                    "additionalProperties": false
                  },
                  {
                    "type": "object",
                    "description": "Editable native geometry and paint. Fill and stroke can be solid or a gradient.",
                    "properties": {
                      "type": {
                        "type": "string",
                        "description": "Component type.",
                        "enum": [
                          "shape"
                        ]
                      },
                      "id": {
                        "type": "string",
                        "description": "Existing saved native UID. It is not an array index or an AI-generated identity.",
                        "maxLength": 128,
                        "minLength": 8,
                        "pattern": "^[A-Za-z0-9_-]{8,128}$"
                      },
                      "layer": {
                        "type": "integer",
                        "description": "Native layer, zero is bottom. Each layer is a vertical stack, as in the editor: array order is the stack order, the first element's y is the top of the stack and each later element starts where the one above ends (its y is derived). Put elements that should overlap or sit freely in separate layers. Empty layers are removed.",
                        "minimum": 0,
                        "maximum": 14
                      },
                      "location": {
                        "type": "object",
                        "description": "Native rectangle. In % mode 0.5 is half the canvas, NOT 50; x/y range -5..5, width/height 0..5. In px mode x/y range -100000..100000, width/height 0..100000. x/y locate the rectangle; anchor does not shift its origin.",
                        "properties": {
                          "x": {
                            "type": "number",
                            "description": "Rectangle X. Bounds depend on units.",
                            "minimum": -100000,
                            "maximum": 100000
                          },
                          "y": {
                            "type": "number",
                            "description": "Rectangle Y.",
                            "minimum": -100000,
                            "maximum": 100000
                          },
                          "width": {
                            "type": "number",
                            "description": "Rectangle width; zero-size existing objects are valid.",
                            "minimum": 0,
                            "maximum": 100000
                          },
                          "height": {
                            "type": "number",
                            "description": "Rectangle height.",
                            "minimum": 0,
                            "maximum": 100000
                          },
                          "units": {
                            "type": "string",
                            "description": "Native % fractions or px. Values are not converted when changing units.",
                            "enum": [
                              "px",
                              "%"
                            ]
                          },
                          "anchor": {
                            "type": "string",
                            "description": "Text uses this for vertical placement. For images, devices and shapes this legacy field is preserved but does not position content; use position instead.",
                            "enum": [
                              "topMiddle",
                              "topLeft",
                              "topRight",
                              "middle",
                              "middleLeft",
                              "middleRight",
                              "bottomMiddle",
                              "bottomLeft",
                              "bottomRight"
                            ]
                          }
                        },
                        "required": [
                          "x",
                          "y",
                          "width",
                          "height",
                          "units",
                          "anchor"
                        ],
                        "additionalProperties": false
                      },
                      "rotation": {
                        "type": "number",
                        "description": "Rotation in degrees, not radians; perspective is a device frame variant, not arbitrary 3D.",
                        "minimum": -359,
                        "maximum": 359
                      },
                      "opacity": {
                        "type": "integer",
                        "description": "Element opacity percentage. 0 is transparent and 100 is fully opaque. AppScreens stores 100 as its native null/default, but this document always exposes the effective percentage.",
                        "minimum": 0,
                        "maximum": 100
                      },
                      "shadow": {
                        "type": "object",
                        "description": "Native relative shadow. Rendering scales offsets/blur by 0.04 times its reference size, normally full canvas height, NOT pixels. Color null with global false disables the shadow; shadow null itself resets native defaults. Inherited shadows are preserved.",
                        "properties": {
                          "color": {
                            "anyOf": [
                              {
                                "type": "object",
                                "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                "properties": {
                                  "rgba": {
                                    "type": "array",
                                    "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                    "items": {
                                      "type": "number",
                                      "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                      "minimum": 0,
                                      "maximum": 255
                                    },
                                    "maxItems": 4,
                                    "minItems": 4
                                  }
                                },
                                "required": [
                                  "rgba"
                                ],
                                "additionalProperties": false
                              },
                              {
                                "type": "null"
                              }
                            ],
                            "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA."
                          },
                          "x": {
                            "type": "number",
                            "description": "Native horizontal offset. 0.125 is 0.5% of reference size.",
                            "minimum": -0.86,
                            "maximum": 0.86
                          },
                          "y": {
                            "type": "number",
                            "description": "Native vertical offset.",
                            "minimum": -0.86,
                            "maximum": 0.86
                          },
                          "blur": {
                            "type": "number",
                            "description": "Native blur; 0.25 is 1% of reference size.",
                            "minimum": 0,
                            "maximum": 2.5
                          },
                          "global": {
                            "type": "boolean",
                            "description": "True inherits the project shadow. False uses this explicit shadow."
                          }
                        },
                        "required": [
                          "color",
                          "x",
                          "y",
                          "blur",
                          "global"
                        ],
                        "additionalProperties": false
                      },
                      "shape": {
                        "type": "string",
                        "description": "Native shape.",
                        "enum": [
                          "rectangle",
                          "square",
                          "circle",
                          "ellipse",
                          "triangle",
                          "line"
                        ]
                      },
                      "fit": {
                        "type": "string",
                        "description": "Native shape sizing mode, including fill.",
                        "enum": [
                          "fill",
                          "contain",
                          "covertop",
                          "coverbottom",
                          "covercenter"
                        ]
                      },
                      "lineDirection": {
                        "type": "string",
                        "description": "Line shapes only.",
                        "enum": [
                          "horizontal",
                          "vertical"
                        ]
                      },
                      "position": {
                        "type": "string",
                        "description": "Content anchor. Horizontal lines use topMiddle/middle/bottomMiddle; vertical lines use middleLeft/middle/middleRight. Other saved line anchors render at the centre.",
                        "enum": [
                          "topMiddle",
                          "topLeft",
                          "topRight",
                          "middle",
                          "middleLeft",
                          "middleRight",
                          "bottomMiddle",
                          "bottomLeft",
                          "bottomRight"
                        ]
                      },
                      "boundary": {
                        "type": "string",
                        "description": "How rotation meets the box. inside (the default): the rotated content is scaled down until its rotated bounds fit the unrotated box, so a tilted wide image draws smaller, by min(W / (w cos a + h sin a), H / (h cos a + w sin a)) for content w x h in box W x H. outside: the box itself turns and the content keeps its size, so its corners can pass the box. Use outside to tilt a card without shrinking it.",
                        "enum": [
                          "inside",
                          "outside"
                        ]
                      },
                      "fill": {
                        "anyOf": [
                          {
                            "anyOf": [
                              {
                                "type": "object",
                                "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                "properties": {
                                  "rgba": {
                                    "type": "array",
                                    "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                    "items": {
                                      "type": "number",
                                      "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                      "minimum": 0,
                                      "maximum": 255
                                    },
                                    "maxItems": 4,
                                    "minItems": 4
                                  }
                                },
                                "required": [
                                  "rgba"
                                ],
                                "additionalProperties": false
                              },
                              {
                                "type": "object",
                                "description": "Gradient paint.",
                                "properties": {
                                  "gradient": {
                                    "type": "object",
                                    "description": "Two-colour gradient, as the editor's gradient picker makes it.",
                                    "properties": {
                                      "style": {
                                        "type": "string",
                                        "description": "linear, or radial from the centre point.",
                                        "enum": [
                                          "linear",
                                          "radial"
                                        ]
                                      },
                                      "angle": {
                                        "type": "number",
                                        "description": "Linear: angle in degrees. Radial: radius as a percentage (1..100), centred in the painted area.",
                                        "minimum": -360,
                                        "maximum": 360
                                      },
                                      "from": {
                                        "type": "object",
                                        "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                        "properties": {
                                          "rgba": {
                                            "type": "array",
                                            "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                            "items": {
                                              "type": "number",
                                              "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                              "minimum": 0,
                                              "maximum": 255
                                            },
                                            "maxItems": 4,
                                            "minItems": 4
                                          }
                                        },
                                        "required": [
                                          "rgba"
                                        ],
                                        "additionalProperties": false
                                      },
                                      "to": {
                                        "type": "object",
                                        "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                        "properties": {
                                          "rgba": {
                                            "type": "array",
                                            "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                            "items": {
                                              "type": "number",
                                              "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                              "minimum": 0,
                                              "maximum": 255
                                            },
                                            "maxItems": 4,
                                            "minItems": 4
                                          }
                                        },
                                        "required": [
                                          "rgba"
                                        ],
                                        "additionalProperties": false
                                      },
                                      "stopFrom": {
                                        "type": "number",
                                        "description": "Where the first colour stops, 0..1.",
                                        "minimum": 0,
                                        "maximum": 1
                                      },
                                      "stopTo": {
                                        "type": "number",
                                        "description": "Where the second colour starts, 0..1.",
                                        "minimum": 0,
                                        "maximum": 1
                                      }
                                    },
                                    "required": [
                                      "style",
                                      "angle",
                                      "from",
                                      "to",
                                      "stopFrom",
                                      "stopTo"
                                    ],
                                    "additionalProperties": false
                                  }
                                },
                                "required": [
                                  "gradient"
                                ],
                                "additionalProperties": false
                              }
                            ],
                            "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
                          },
                          {
                            "type": "null"
                          }
                        ],
                        "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
                      },
                      "stroke": {
                        "anyOf": [
                          {
                            "anyOf": [
                              {
                                "type": "object",
                                "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                "properties": {
                                  "rgba": {
                                    "type": "array",
                                    "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                    "items": {
                                      "type": "number",
                                      "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                      "minimum": 0,
                                      "maximum": 255
                                    },
                                    "maxItems": 4,
                                    "minItems": 4
                                  }
                                },
                                "required": [
                                  "rgba"
                                ],
                                "additionalProperties": false
                              },
                              {
                                "type": "object",
                                "description": "Gradient paint.",
                                "properties": {
                                  "gradient": {
                                    "type": "object",
                                    "description": "Two-colour gradient, as the editor's gradient picker makes it.",
                                    "properties": {
                                      "style": {
                                        "type": "string",
                                        "description": "linear, or radial from the centre point.",
                                        "enum": [
                                          "linear",
                                          "radial"
                                        ]
                                      },
                                      "angle": {
                                        "type": "number",
                                        "description": "Linear: angle in degrees. Radial: radius as a percentage (1..100), centred in the painted area.",
                                        "minimum": -360,
                                        "maximum": 360
                                      },
                                      "from": {
                                        "type": "object",
                                        "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                        "properties": {
                                          "rgba": {
                                            "type": "array",
                                            "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                            "items": {
                                              "type": "number",
                                              "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                              "minimum": 0,
                                              "maximum": 255
                                            },
                                            "maxItems": 4,
                                            "minItems": 4
                                          }
                                        },
                                        "required": [
                                          "rgba"
                                        ],
                                        "additionalProperties": false
                                      },
                                      "to": {
                                        "type": "object",
                                        "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                        "properties": {
                                          "rgba": {
                                            "type": "array",
                                            "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                            "items": {
                                              "type": "number",
                                              "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                              "minimum": 0,
                                              "maximum": 255
                                            },
                                            "maxItems": 4,
                                            "minItems": 4
                                          }
                                        },
                                        "required": [
                                          "rgba"
                                        ],
                                        "additionalProperties": false
                                      },
                                      "stopFrom": {
                                        "type": "number",
                                        "description": "Where the first colour stops, 0..1.",
                                        "minimum": 0,
                                        "maximum": 1
                                      },
                                      "stopTo": {
                                        "type": "number",
                                        "description": "Where the second colour starts, 0..1.",
                                        "minimum": 0,
                                        "maximum": 1
                                      }
                                    },
                                    "required": [
                                      "style",
                                      "angle",
                                      "from",
                                      "to",
                                      "stopFrom",
                                      "stopTo"
                                    ],
                                    "additionalProperties": false
                                  }
                                },
                                "required": [
                                  "gradient"
                                ],
                                "additionalProperties": false
                              }
                            ],
                            "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
                          },
                          {
                            "type": "null"
                          }
                        ],
                        "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
                      },
                      "strokeWidth": {
                        "type": "number",
                        "description": "PERCENT; 2 means 2%, not 0.02. Of the shortest rendered edge, except a line with lineStrokeCanvas true: of canvas height, capped to the line box thickness.",
                        "minimum": 0,
                        "maximum": 100
                      },
                      "lineStrokeCanvas": {
                        "type": "boolean",
                        "description": "Line shapes only. True keeps strokeWidth a percent of canvas height, so resizing the box does not change it. False or unset is the legacy shortest-edge stroke. New editor lines use true."
                      },
                      "cornerRadius": {
                        "type": "number",
                        "description": "PERCENT of shortest rendered edge.",
                        "minimum": 0,
                        "maximum": 50
                      }
                    },
                    "required": [
                      "type",
                      "id",
                      "layer",
                      "opacity"
                    ],
                    "additionalProperties": false
                  },
                  {
                    "type": "object",
                    "description": "Native image overlay. Asset pixels and SVG path geometry remain native-owned. Source slots, SVG colour/stroke styling and the frame (corner rounding, border, fill, padding) are editable. Fill shows behind transparent pixels and around a padded image.",
                    "properties": {
                      "type": {
                        "type": "string",
                        "description": "Component type.",
                        "enum": [
                          "image"
                        ]
                      },
                      "id": {
                        "type": "string",
                        "description": "Existing saved native UID. It is not an array index or an AI-generated identity.",
                        "maxLength": 128,
                        "minLength": 8,
                        "pattern": "^[A-Za-z0-9_-]{8,128}$"
                      },
                      "layer": {
                        "type": "integer",
                        "description": "Native layer, zero is bottom. Each layer is a vertical stack, as in the editor: array order is the stack order, the first element's y is the top of the stack and each later element starts where the one above ends (its y is derived). Put elements that should overlap or sit freely in separate layers. Empty layers are removed.",
                        "minimum": 0,
                        "maximum": 14
                      },
                      "location": {
                        "type": "object",
                        "description": "Native rectangle. In % mode 0.5 is half the canvas, NOT 50; x/y range -5..5, width/height 0..5. In px mode x/y range -100000..100000, width/height 0..100000. x/y locate the rectangle; anchor does not shift its origin.",
                        "properties": {
                          "x": {
                            "type": "number",
                            "description": "Rectangle X. Bounds depend on units.",
                            "minimum": -100000,
                            "maximum": 100000
                          },
                          "y": {
                            "type": "number",
                            "description": "Rectangle Y.",
                            "minimum": -100000,
                            "maximum": 100000
                          },
                          "width": {
                            "type": "number",
                            "description": "Rectangle width; zero-size existing objects are valid.",
                            "minimum": 0,
                            "maximum": 100000
                          },
                          "height": {
                            "type": "number",
                            "description": "Rectangle height.",
                            "minimum": 0,
                            "maximum": 100000
                          },
                          "units": {
                            "type": "string",
                            "description": "Native % fractions or px. Values are not converted when changing units.",
                            "enum": [
                              "px",
                              "%"
                            ]
                          },
                          "anchor": {
                            "type": "string",
                            "description": "Text uses this for vertical placement. For images, devices and shapes this legacy field is preserved but does not position content; use position instead.",
                            "enum": [
                              "topMiddle",
                              "topLeft",
                              "topRight",
                              "middle",
                              "middleLeft",
                              "middleRight",
                              "bottomMiddle",
                              "bottomLeft",
                              "bottomRight"
                            ]
                          }
                        },
                        "required": [
                          "x",
                          "y",
                          "width",
                          "height",
                          "units",
                          "anchor"
                        ],
                        "additionalProperties": false
                      },
                      "rotation": {
                        "type": "number",
                        "description": "Rotation in degrees, not radians; perspective is a device frame variant, not arbitrary 3D.",
                        "minimum": -359,
                        "maximum": 359
                      },
                      "opacity": {
                        "type": "integer",
                        "description": "Element opacity percentage. 0 is transparent and 100 is fully opaque. AppScreens stores 100 as its native null/default, but this document always exposes the effective percentage.",
                        "minimum": 0,
                        "maximum": 100
                      },
                      "slots": {
                        "type": "array",
                        "description": "Only existing explicit source assignments. Empty slots/fallbacks are not materialized. Each field/language/target combination must remain present and unchanged; only assetId can change.",
                        "items": {
                          "type": "object",
                          "description": "One source assignment.",
                          "properties": {
                            "field": {
                              "type": "string",
                              "description": "Original storage provenance.",
                              "enum": [
                                "base",
                                "translation",
                                "legacy"
                              ]
                            },
                            "language": {
                              "type": "string",
                              "description": "An existing language or target key. It cannot create languages or targets.",
                              "maxLength": 128,
                              "minLength": 1,
                              "pattern": "^[A-Za-z0-9_-]{1,128}$"
                            },
                            "targetId": {
                              "type": "string",
                              "description": "An existing language or target key. It cannot create languages or targets.",
                              "maxLength": 128,
                              "minLength": 1,
                              "pattern": "^[A-Za-z0-9_-]{1,128}$"
                            },
                            "assetId": {
                              "type": "string",
                              "description": "Approved stable asset ID. Never a URL, data URI, signed URL or token.",
                              "maxLength": 1024,
                              "minLength": 1
                            }
                          },
                          "required": [
                            "field",
                            "language",
                            "targetId",
                            "assetId"
                          ],
                          "additionalProperties": false
                        },
                        "maxItems": 500,
                        "minItems": 0
                      },
                      "fit": {
                        "type": "string",
                        "description": "Native contain or width-cover alignment. There is no cover/fill image mode.",
                        "enum": [
                          "contain",
                          "covertop",
                          "coverbottom",
                          "covercenter"
                        ]
                      },
                      "position": {
                        "type": "string",
                        "description": "Fitted source anchor.",
                        "enum": [
                          "topMiddle",
                          "topLeft",
                          "topRight",
                          "middle",
                          "middleLeft",
                          "middleRight",
                          "bottomMiddle",
                          "bottomLeft",
                          "bottomRight"
                        ]
                      },
                      "boundary": {
                        "type": "string",
                        "description": "How rotation meets the box. inside (the default): the rotated content is scaled down until its rotated bounds fit the unrotated box, so a tilted wide image draws smaller, by min(W / (w cos a + h sin a), H / (h cos a + w sin a)) for content w x h in box W x H. outside: the box itself turns and the content keeps its size, so its corners can pass the box. Use outside to tilt a card without shrinking it.",
                        "enum": [
                          "inside",
                          "outside"
                        ]
                      },
                      "shadow": {
                        "type": "object",
                        "description": "Native relative shadow. Rendering scales offsets/blur by 0.04 times its reference size, normally full canvas height, NOT pixels. Color null with global false disables the shadow; shadow null itself resets native defaults. Inherited shadows are preserved.",
                        "properties": {
                          "color": {
                            "anyOf": [
                              {
                                "type": "object",
                                "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                "properties": {
                                  "rgba": {
                                    "type": "array",
                                    "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                    "items": {
                                      "type": "number",
                                      "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                      "minimum": 0,
                                      "maximum": 255
                                    },
                                    "maxItems": 4,
                                    "minItems": 4
                                  }
                                },
                                "required": [
                                  "rgba"
                                ],
                                "additionalProperties": false
                              },
                              {
                                "type": "null"
                              }
                            ],
                            "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA."
                          },
                          "x": {
                            "type": "number",
                            "description": "Native horizontal offset. 0.125 is 0.5% of reference size.",
                            "minimum": -0.86,
                            "maximum": 0.86
                          },
                          "y": {
                            "type": "number",
                            "description": "Native vertical offset.",
                            "minimum": -0.86,
                            "maximum": 0.86
                          },
                          "blur": {
                            "type": "number",
                            "description": "Native blur; 0.25 is 1% of reference size.",
                            "minimum": 0,
                            "maximum": 2.5
                          },
                          "global": {
                            "type": "boolean",
                            "description": "True inherits the project shadow. False uses this explicit shadow."
                          }
                        },
                        "required": [
                          "color",
                          "x",
                          "y",
                          "blur",
                          "global"
                        ],
                        "additionalProperties": false
                      },
                      "svgOverlayColor": {
                        "anyOf": [
                          {
                            "anyOf": [
                              {
                                "type": "object",
                                "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                "properties": {
                                  "rgba": {
                                    "type": "array",
                                    "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                    "items": {
                                      "type": "number",
                                      "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                      "minimum": 0,
                                      "maximum": 255
                                    },
                                    "maxItems": 4,
                                    "minItems": 4
                                  }
                                },
                                "required": [
                                  "rgba"
                                ],
                                "additionalProperties": false
                              },
                              {
                                "type": "object",
                                "description": "Gradient paint.",
                                "properties": {
                                  "gradient": {
                                    "type": "object",
                                    "description": "Two-colour gradient, as the editor's gradient picker makes it.",
                                    "properties": {
                                      "style": {
                                        "type": "string",
                                        "description": "linear, or radial from the centre point.",
                                        "enum": [
                                          "linear",
                                          "radial"
                                        ]
                                      },
                                      "angle": {
                                        "type": "number",
                                        "description": "Linear: angle in degrees. Radial: radius as a percentage (1..100), centred in the painted area.",
                                        "minimum": -360,
                                        "maximum": 360
                                      },
                                      "from": {
                                        "type": "object",
                                        "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                        "properties": {
                                          "rgba": {
                                            "type": "array",
                                            "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                            "items": {
                                              "type": "number",
                                              "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                              "minimum": 0,
                                              "maximum": 255
                                            },
                                            "maxItems": 4,
                                            "minItems": 4
                                          }
                                        },
                                        "required": [
                                          "rgba"
                                        ],
                                        "additionalProperties": false
                                      },
                                      "to": {
                                        "type": "object",
                                        "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                        "properties": {
                                          "rgba": {
                                            "type": "array",
                                            "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                            "items": {
                                              "type": "number",
                                              "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                              "minimum": 0,
                                              "maximum": 255
                                            },
                                            "maxItems": 4,
                                            "minItems": 4
                                          }
                                        },
                                        "required": [
                                          "rgba"
                                        ],
                                        "additionalProperties": false
                                      },
                                      "stopFrom": {
                                        "type": "number",
                                        "description": "Where the first colour stops, 0..1.",
                                        "minimum": 0,
                                        "maximum": 1
                                      },
                                      "stopTo": {
                                        "type": "number",
                                        "description": "Where the second colour starts, 0..1.",
                                        "minimum": 0,
                                        "maximum": 1
                                      }
                                    },
                                    "required": [
                                      "style",
                                      "angle",
                                      "from",
                                      "to",
                                      "stopFrom",
                                      "stopTo"
                                    ],
                                    "additionalProperties": false
                                  }
                                },
                                "required": [
                                  "gradient"
                                ],
                                "additionalProperties": false
                              }
                            ],
                            "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
                          },
                          {
                            "type": "null"
                          }
                        ],
                        "description": "SVG colour overlay, solid or gradient. Recolours existing visible fills and, without an explicit SVG stroke, existing strokes. Null or transparent means keep original artwork colours. No effect on raster images."
                      },
                      "svgStrokeColor": {
                        "anyOf": [
                          {
                            "anyOf": [
                              {
                                "type": "object",
                                "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                "properties": {
                                  "rgba": {
                                    "type": "array",
                                    "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                    "items": {
                                      "type": "number",
                                      "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                      "minimum": 0,
                                      "maximum": 255
                                    },
                                    "maxItems": 4,
                                    "minItems": 4
                                  }
                                },
                                "required": [
                                  "rgba"
                                ],
                                "additionalProperties": false
                              },
                              {
                                "type": "object",
                                "description": "Gradient paint.",
                                "properties": {
                                  "gradient": {
                                    "type": "object",
                                    "description": "Two-colour gradient, as the editor's gradient picker makes it.",
                                    "properties": {
                                      "style": {
                                        "type": "string",
                                        "description": "linear, or radial from the centre point.",
                                        "enum": [
                                          "linear",
                                          "radial"
                                        ]
                                      },
                                      "angle": {
                                        "type": "number",
                                        "description": "Linear: angle in degrees. Radial: radius as a percentage (1..100), centred in the painted area.",
                                        "minimum": -360,
                                        "maximum": 360
                                      },
                                      "from": {
                                        "type": "object",
                                        "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                        "properties": {
                                          "rgba": {
                                            "type": "array",
                                            "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                            "items": {
                                              "type": "number",
                                              "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                              "minimum": 0,
                                              "maximum": 255
                                            },
                                            "maxItems": 4,
                                            "minItems": 4
                                          }
                                        },
                                        "required": [
                                          "rgba"
                                        ],
                                        "additionalProperties": false
                                      },
                                      "to": {
                                        "type": "object",
                                        "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                        "properties": {
                                          "rgba": {
                                            "type": "array",
                                            "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                            "items": {
                                              "type": "number",
                                              "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                              "minimum": 0,
                                              "maximum": 255
                                            },
                                            "maxItems": 4,
                                            "minItems": 4
                                          }
                                        },
                                        "required": [
                                          "rgba"
                                        ],
                                        "additionalProperties": false
                                      },
                                      "stopFrom": {
                                        "type": "number",
                                        "description": "Where the first colour stops, 0..1.",
                                        "minimum": 0,
                                        "maximum": 1
                                      },
                                      "stopTo": {
                                        "type": "number",
                                        "description": "Where the second colour starts, 0..1.",
                                        "minimum": 0,
                                        "maximum": 1
                                      }
                                    },
                                    "required": [
                                      "style",
                                      "angle",
                                      "from",
                                      "to",
                                      "stopFrom",
                                      "stopTo"
                                    ],
                                    "additionalProperties": false
                                  }
                                },
                                "required": [
                                  "gradient"
                                ],
                                "additionalProperties": false
                              }
                            ],
                            "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
                          },
                          {
                            "type": "null"
                          }
                        ],
                        "description": "SVG path stroke, solid or gradient. Null or transparent keeps the source stroke. Uses svgStrokeWidth, not the image frame borderWidth."
                      },
                      "svgStrokeWidth": {
                        "type": "number",
                        "description": "Fraction of full canvas height, as the editor SVG stroke control: 0.01 means 1%. Needs svgStrokeColor. No effect on raster images.",
                        "minimum": 0,
                        "maximum": 0.2
                      },
                      "cornerRadius": {
                        "type": "number",
                        "description": "PERCENT of the shortest visible image edge; 50 is a circle or pill. Rounds the whole frame: fill, border and image follow it, and a padded image rounds by cornerRadius minus padding. Any frame setting clips width-cover overflow to the box.",
                        "minimum": 0,
                        "maximum": 50
                      },
                      "border": {
                        "anyOf": [
                          {
                            "anyOf": [
                              {
                                "type": "object",
                                "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                "properties": {
                                  "rgba": {
                                    "type": "array",
                                    "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                    "items": {
                                      "type": "number",
                                      "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                      "minimum": 0,
                                      "maximum": 255
                                    },
                                    "maxItems": 4,
                                    "minItems": 4
                                  }
                                },
                                "required": [
                                  "rgba"
                                ],
                                "additionalProperties": false
                              },
                              {
                                "type": "object",
                                "description": "Gradient paint.",
                                "properties": {
                                  "gradient": {
                                    "type": "object",
                                    "description": "Two-colour gradient, as the editor's gradient picker makes it.",
                                    "properties": {
                                      "style": {
                                        "type": "string",
                                        "description": "linear, or radial from the centre point.",
                                        "enum": [
                                          "linear",
                                          "radial"
                                        ]
                                      },
                                      "angle": {
                                        "type": "number",
                                        "description": "Linear: angle in degrees. Radial: radius as a percentage (1..100), centred in the painted area.",
                                        "minimum": -360,
                                        "maximum": 360
                                      },
                                      "from": {
                                        "type": "object",
                                        "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                        "properties": {
                                          "rgba": {
                                            "type": "array",
                                            "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                            "items": {
                                              "type": "number",
                                              "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                              "minimum": 0,
                                              "maximum": 255
                                            },
                                            "maxItems": 4,
                                            "minItems": 4
                                          }
                                        },
                                        "required": [
                                          "rgba"
                                        ],
                                        "additionalProperties": false
                                      },
                                      "to": {
                                        "type": "object",
                                        "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                        "properties": {
                                          "rgba": {
                                            "type": "array",
                                            "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                            "items": {
                                              "type": "number",
                                              "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                              "minimum": 0,
                                              "maximum": 255
                                            },
                                            "maxItems": 4,
                                            "minItems": 4
                                          }
                                        },
                                        "required": [
                                          "rgba"
                                        ],
                                        "additionalProperties": false
                                      },
                                      "stopFrom": {
                                        "type": "number",
                                        "description": "Where the first colour stops, 0..1.",
                                        "minimum": 0,
                                        "maximum": 1
                                      },
                                      "stopTo": {
                                        "type": "number",
                                        "description": "Where the second colour starts, 0..1.",
                                        "minimum": 0,
                                        "maximum": 1
                                      }
                                    },
                                    "required": [
                                      "style",
                                      "angle",
                                      "from",
                                      "to",
                                      "stopFrom",
                                      "stopTo"
                                    ],
                                    "additionalProperties": false
                                  }
                                },
                                "required": [
                                  "gradient"
                                ],
                                "additionalProperties": false
                              }
                            ],
                            "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
                          },
                          {
                            "type": "null"
                          }
                        ],
                        "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
                      },
                      "borderWidth": {
                        "type": "number",
                        "description": "PERCENT; 2 means 2%, not 0.02. Of the shortest visible image edge, drawn inside the image edge. Needs a border paint.",
                        "minimum": 0,
                        "maximum": 50
                      },
                      "fill": {
                        "anyOf": [
                          {
                            "anyOf": [
                              {
                                "type": "object",
                                "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                "properties": {
                                  "rgba": {
                                    "type": "array",
                                    "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                    "items": {
                                      "type": "number",
                                      "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                      "minimum": 0,
                                      "maximum": 255
                                    },
                                    "maxItems": 4,
                                    "minItems": 4
                                  }
                                },
                                "required": [
                                  "rgba"
                                ],
                                "additionalProperties": false
                              },
                              {
                                "type": "object",
                                "description": "Gradient paint.",
                                "properties": {
                                  "gradient": {
                                    "type": "object",
                                    "description": "Two-colour gradient, as the editor's gradient picker makes it.",
                                    "properties": {
                                      "style": {
                                        "type": "string",
                                        "description": "linear, or radial from the centre point.",
                                        "enum": [
                                          "linear",
                                          "radial"
                                        ]
                                      },
                                      "angle": {
                                        "type": "number",
                                        "description": "Linear: angle in degrees. Radial: radius as a percentage (1..100), centred in the painted area.",
                                        "minimum": -360,
                                        "maximum": 360
                                      },
                                      "from": {
                                        "type": "object",
                                        "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                        "properties": {
                                          "rgba": {
                                            "type": "array",
                                            "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                            "items": {
                                              "type": "number",
                                              "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                              "minimum": 0,
                                              "maximum": 255
                                            },
                                            "maxItems": 4,
                                            "minItems": 4
                                          }
                                        },
                                        "required": [
                                          "rgba"
                                        ],
                                        "additionalProperties": false
                                      },
                                      "to": {
                                        "type": "object",
                                        "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                                        "properties": {
                                          "rgba": {
                                            "type": "array",
                                            "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                            "items": {
                                              "type": "number",
                                              "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                              "minimum": 0,
                                              "maximum": 255
                                            },
                                            "maxItems": 4,
                                            "minItems": 4
                                          }
                                        },
                                        "required": [
                                          "rgba"
                                        ],
                                        "additionalProperties": false
                                      },
                                      "stopFrom": {
                                        "type": "number",
                                        "description": "Where the first colour stops, 0..1.",
                                        "minimum": 0,
                                        "maximum": 1
                                      },
                                      "stopTo": {
                                        "type": "number",
                                        "description": "Where the second colour starts, 0..1.",
                                        "minimum": 0,
                                        "maximum": 1
                                      }
                                    },
                                    "required": [
                                      "style",
                                      "angle",
                                      "from",
                                      "to",
                                      "stopFrom",
                                      "stopTo"
                                    ],
                                    "additionalProperties": false
                                  }
                                },
                                "required": [
                                  "gradient"
                                ],
                                "additionalProperties": false
                              }
                            ],
                            "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
                          },
                          {
                            "type": "null"
                          }
                        ],
                        "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
                      },
                      "padding": {
                        "type": "number",
                        "description": "PERCENT of the shortest visible image edge. Insets the image inside its frame so the fill shows around it; the frame keeps its size.",
                        "minimum": 0,
                        "maximum": 40
                      }
                    },
                    "required": [
                      "type",
                      "id",
                      "layer",
                      "opacity",
                      "slots"
                    ],
                    "additionalProperties": false
                  },
                  {
                    "type": "object",
                    "description": "An unsupported native object, kept editable in AppScreens. Only layer placement/order can change in this draft; no opaque native properties are returned.",
                    "properties": {
                      "type": {
                        "type": "string",
                        "description": "Component type.",
                        "enum": [
                          "preserved"
                        ]
                      },
                      "id": {
                        "type": "string",
                        "description": "Existing saved native UID. It is not an array index or an AI-generated identity.",
                        "maxLength": 128,
                        "minLength": 8,
                        "pattern": "^[A-Za-z0-9_-]{8,128}$"
                      },
                      "layer": {
                        "type": "integer",
                        "description": "Native layer, zero is bottom. Each layer is a vertical stack, as in the editor: array order is the stack order, the first element's y is the top of the stack and each later element starts where the one above ends (its y is derived). Put elements that should overlap or sit freely in separate layers. Empty layers are removed.",
                        "minimum": 0,
                        "maximum": 14
                      }
                    },
                    "required": [
                      "type",
                      "id",
                      "layer"
                    ],
                    "additionalProperties": false
                  }
                ]
              },
              "maxItems": 100,
              "minItems": 0
            }
          },
          "required": [
            "id",
            "elements"
          ],
          "additionalProperties": false
        },
        "maxItems": 1,
        "minItems": 1
      }
    },
    "required": [
      "version",
      "screenshots"
    ],
    "additionalProperties": false
  },
  "components": {
    "device": {
      "type": "object",
      "description": "Native device frame and genuine app screenshot. Enum validity does not prove frame/appearance availability for every output target; preview and existing preflight remain mandatory.",
      "properties": {
        "type": {
          "type": "string",
          "description": "Component type.",
          "enum": [
            "device"
          ]
        },
        "id": {
          "type": "string",
          "description": "Existing saved native UID. It is not an array index or an AI-generated identity.",
          "maxLength": 128,
          "minLength": 8,
          "pattern": "^[A-Za-z0-9_-]{8,128}$"
        },
        "layer": {
          "type": "integer",
          "description": "Native layer, zero is bottom. Each layer is a vertical stack, as in the editor: array order is the stack order, the first element's y is the top of the stack and each later element starts where the one above ends (its y is derived). Put elements that should overlap or sit freely in separate layers. Empty layers are removed.",
          "minimum": 0,
          "maximum": 14
        },
        "location": {
          "type": "object",
          "description": "Native rectangle. In % mode 0.5 is half the canvas, NOT 50; x/y range -5..5, width/height 0..5. In px mode x/y range -100000..100000, width/height 0..100000. x/y locate the rectangle; anchor does not shift its origin.",
          "properties": {
            "x": {
              "type": "number",
              "description": "Rectangle X. Bounds depend on units.",
              "minimum": -100000,
              "maximum": 100000
            },
            "y": {
              "type": "number",
              "description": "Rectangle Y.",
              "minimum": -100000,
              "maximum": 100000
            },
            "width": {
              "type": "number",
              "description": "Rectangle width; zero-size existing objects are valid.",
              "minimum": 0,
              "maximum": 100000
            },
            "height": {
              "type": "number",
              "description": "Rectangle height.",
              "minimum": 0,
              "maximum": 100000
            },
            "units": {
              "type": "string",
              "description": "Native % fractions or px. Values are not converted when changing units.",
              "enum": [
                "px",
                "%"
              ]
            },
            "anchor": {
              "type": "string",
              "description": "Text uses this for vertical placement. For images, devices and shapes this legacy field is preserved but does not position content; use position instead.",
              "enum": [
                "topMiddle",
                "topLeft",
                "topRight",
                "middle",
                "middleLeft",
                "middleRight",
                "bottomMiddle",
                "bottomLeft",
                "bottomRight"
              ]
            }
          },
          "required": [
            "x",
            "y",
            "width",
            "height",
            "units",
            "anchor"
          ],
          "additionalProperties": false
        },
        "rotation": {
          "type": "number",
          "description": "Rotation in degrees, not radians; perspective is a device frame variant, not arbitrary 3D.",
          "minimum": -359,
          "maximum": 359
        },
        "opacity": {
          "type": "integer",
          "description": "Element opacity percentage. 0 is transparent and 100 is fully opaque. AppScreens stores 100 as its native null/default, but this document always exposes the effective percentage.",
          "minimum": 0,
          "maximum": 100
        },
        "slots": {
          "type": "array",
          "description": "Only existing explicit source assignments. Empty slots/fallbacks are not materialized. Each field/language/target combination must remain present and unchanged; only assetId can change.",
          "items": {
            "type": "object",
            "description": "One source assignment.",
            "properties": {
              "field": {
                "type": "string",
                "description": "Original storage provenance.",
                "enum": [
                  "base",
                  "translation",
                  "legacy"
                ]
              },
              "language": {
                "type": "string",
                "description": "An existing language or target key. It cannot create languages or targets.",
                "maxLength": 128,
                "minLength": 1,
                "pattern": "^[A-Za-z0-9_-]{1,128}$"
              },
              "targetId": {
                "type": "string",
                "description": "An existing language or target key. It cannot create languages or targets.",
                "maxLength": 128,
                "minLength": 1,
                "pattern": "^[A-Za-z0-9_-]{1,128}$"
              },
              "assetId": {
                "type": "string",
                "description": "Approved stable asset ID. Never a URL, data URI, signed URL or token.",
                "maxLength": 1024,
                "minLength": 1
              }
            },
            "required": [
              "field",
              "language",
              "targetId",
              "assetId"
            ],
            "additionalProperties": false
          },
          "maxItems": 500,
          "minItems": 0
        },
        "fit": {
          "type": "string",
          "description": "Native contain or width-cover alignment. There is no cover/fill image mode.",
          "enum": [
            "contain",
            "covertop",
            "coverbottom",
            "covercenter"
          ]
        },
        "position": {
          "type": "string",
          "description": "Fitted source anchor.",
          "enum": [
            "topMiddle",
            "topLeft",
            "topRight",
            "middle",
            "middleLeft",
            "middleRight",
            "bottomMiddle",
            "bottomLeft",
            "bottomRight"
          ]
        },
        "boundary": {
          "type": "string",
          "description": "How rotation meets the box. inside (the default): the rotated content is scaled down until its rotated bounds fit the unrotated box, so a tilted wide image draws smaller, by min(W / (w cos a + h sin a), H / (h cos a + w sin a)) for content w x h in box W x H. outside: the box itself turns and the content keeps its size, so its corners can pass the box. Use outside to tilt a card without shrinking it.",
          "enum": [
            "inside",
            "outside"
          ]
        },
        "shadow": {
          "type": "object",
          "description": "Native relative shadow. Rendering scales offsets/blur by 0.04 times its reference size, normally full canvas height, NOT pixels. Color null with global false disables the shadow; shadow null itself resets native defaults. Inherited shadows are preserved.",
          "properties": {
            "color": {
              "anyOf": [
                {
                  "type": "object",
                  "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                  "properties": {
                    "rgba": {
                      "type": "array",
                      "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                      "items": {
                        "type": "number",
                        "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                        "minimum": 0,
                        "maximum": 255
                      },
                      "maxItems": 4,
                      "minItems": 4
                    }
                  },
                  "required": [
                    "rgba"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "null"
                }
              ],
              "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA."
            },
            "x": {
              "type": "number",
              "description": "Native horizontal offset. 0.125 is 0.5% of reference size.",
              "minimum": -0.86,
              "maximum": 0.86
            },
            "y": {
              "type": "number",
              "description": "Native vertical offset.",
              "minimum": -0.86,
              "maximum": 0.86
            },
            "blur": {
              "type": "number",
              "description": "Native blur; 0.25 is 1% of reference size.",
              "minimum": 0,
              "maximum": 2.5
            },
            "global": {
              "type": "boolean",
              "description": "True inherits the project shadow. False uses this explicit shadow."
            }
          },
          "required": [
            "color",
            "x",
            "y",
            "blur",
            "global"
          ],
          "additionalProperties": false
        },
        "frame": {
          "type": "string",
          "description": "Existing frame variants. Perspective variants are asset-defined, not arbitrary XYZ rotation.",
          "enum": [
            "full",
            "dynamic",
            "none",
            "cover",
            "warpleft",
            "warpright",
            "nonewarpleft",
            "nonewarpright"
          ]
        },
        "appearance": {
          "type": "string",
          "description": "Native appearance. Availability depends on the output target; inspect a rendered preview. Missing frame artwork uses the renderer fallback.",
          "enum": [
            "black",
            "reallight",
            "realgold",
            "light",
            "dark",
            "granite",
            "silver",
            "mint",
            "apple",
            "earth",
            "green",
            "rose",
            "strawberry",
            "bluelagoon",
            "space",
            "berry",
            "lemon",
            "gold",
            "coral"
          ]
        },
        "orientation": {
          "type": "string",
          "description": "Device orientation.",
          "enum": [
            "portrait",
            "landscapeleft",
            "landscaperight"
          ]
        },
        "blankWhenEmpty": {
          "type": "boolean",
          "description": "Show a plain dark screen when no app capture is available. False or unset shows the sample screenshot. Assigned captures take precedence. No asset is created or assigned by this setting."
        },
        "rounding": {
          "anyOf": [
            {
              "type": "number",
              "description": "Corner rounding, as in the editor: null is Auto (the frame's own screen corners) and 0 is None. Only dynamic and frameless variants use it.",
              "minimum": 0,
              "maximum": 0
            },
            {
              "type": "null"
            }
          ],
          "description": "Corner rounding, as in the editor: null is Auto (the frame's own screen corners) and 0 is None. Only dynamic and frameless variants use it."
        },
        "dynamicFrameColor": {
          "anyOf": [
            {
              "type": "object",
              "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
              "properties": {
                "rgba": {
                  "type": "array",
                  "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                  "items": {
                    "type": "number",
                    "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                    "minimum": 0,
                    "maximum": 255
                  },
                  "maxItems": 4,
                  "minItems": 4
                }
              },
              "required": [
                "rgba"
              ],
              "additionalProperties": false
            },
            {
              "type": "null"
            }
          ],
          "description": "Visible solid dynamic frame colour. Changed null/alpha-zero would reset its native default and is rejected."
        },
        "dynamicFrameSize": {
          "type": "number",
          "description": "Fraction of shortest screenshot edge, 0..5%. Only dynamic frames use this.",
          "minimum": 0,
          "maximum": 0.05
        },
        "dynamicPadding": {
          "type": "number",
          "description": "Fraction of shortest screenshot edge, 0..5%. Only dynamic frames use this.",
          "minimum": 0,
          "maximum": 0.05
        },
        "dynamicPaddingColor": {
          "anyOf": [
            {
              "type": "object",
              "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
              "properties": {
                "rgba": {
                  "type": "array",
                  "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                  "items": {
                    "type": "number",
                    "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                    "minimum": 0,
                    "maximum": 255
                  },
                  "maxItems": 4,
                  "minItems": 4
                }
              },
              "required": [
                "rgba"
              ],
              "additionalProperties": false
            },
            {
              "type": "null"
            }
          ],
          "description": "Solid dynamic padding colour, including alpha zero for transparent padding. Null restores the native default white at 20% opacity."
        },
        "dynamicInfill": {
          "anyOf": [
            {
              "type": "object",
              "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
              "properties": {
                "rgba": {
                  "type": "array",
                  "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                  "items": {
                    "type": "number",
                    "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                    "minimum": 0,
                    "maximum": 255
                  },
                  "maxItems": 4,
                  "minItems": 4
                }
              },
              "required": [
                "rgba"
              ],
              "additionalProperties": false
            },
            {
              "type": "null"
            }
          ],
          "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA."
        },
        "displayDevices": {
          "type": "array",
          "description": "Overrides the project display for this frame on a selected output size. Use set_project_settings with patch.targets.targetOverrides for a display shared across the set. Set a layer override only when requested or when this frame needs a different device, such as a watch on a phone page. A \"global\" entry is this layer's fallback when it has no override for the output size. Preserve the list on unrelated edits. Send an empty list only to clear all overrides for this layer.",
          "items": {
            "type": "object",
            "description": "One mapping.",
            "properties": {
              "targetId": {
                "type": "string",
                "description": "An existing language or target key. It cannot create languages or targets.",
                "maxLength": 128,
                "minLength": 1,
                "pattern": "^[A-Za-z0-9_-]{1,128}$"
              },
              "displayDevice": {
                "type": "string",
                "description": "An existing language or target key. It cannot create languages or targets.",
                "maxLength": 128,
                "minLength": 1,
                "pattern": "^[A-Za-z0-9_-]{1,128}$"
              }
            },
            "required": [
              "targetId",
              "displayDevice"
            ],
            "additionalProperties": false
          },
          "maxItems": 100,
          "minItems": 0
        }
      },
      "required": [
        "type",
        "id",
        "layer",
        "opacity",
        "slots"
      ],
      "additionalProperties": false
    },
    "text": {
      "type": "object",
      "description": "Existing title/subtitle group. Common element shadow is not rendered on glyphs, so only title/subtitle block shadow is editable. Translation overrides/inactive locales stay native-only in this draft; use existing text tools for localization.",
      "properties": {
        "type": {
          "type": "string",
          "description": "Component type.",
          "enum": [
            "text"
          ]
        },
        "id": {
          "type": "string",
          "description": "Existing saved native UID. It is not an array index or an AI-generated identity.",
          "maxLength": 128,
          "minLength": 8,
          "pattern": "^[A-Za-z0-9_-]{8,128}$"
        },
        "layer": {
          "type": "integer",
          "description": "Native layer, zero is bottom. Each layer is a vertical stack, as in the editor: array order is the stack order, the first element's y is the top of the stack and each later element starts where the one above ends (its y is derived). Put elements that should overlap or sit freely in separate layers. Empty layers are removed.",
          "minimum": 0,
          "maximum": 14
        },
        "location": {
          "type": "object",
          "description": "Native rectangle. In % mode 0.5 is half the canvas, NOT 50; x/y range -5..5, width/height 0..5. In px mode x/y range -100000..100000, width/height 0..100000. x/y locate the rectangle; anchor does not shift its origin.",
          "properties": {
            "x": {
              "type": "number",
              "description": "Rectangle X. Bounds depend on units.",
              "minimum": -100000,
              "maximum": 100000
            },
            "y": {
              "type": "number",
              "description": "Rectangle Y.",
              "minimum": -100000,
              "maximum": 100000
            },
            "width": {
              "type": "number",
              "description": "Rectangle width; zero-size existing objects are valid.",
              "minimum": 0,
              "maximum": 100000
            },
            "height": {
              "type": "number",
              "description": "Rectangle height.",
              "minimum": 0,
              "maximum": 100000
            },
            "units": {
              "type": "string",
              "description": "Native % fractions or px. Values are not converted when changing units.",
              "enum": [
                "px",
                "%"
              ]
            },
            "anchor": {
              "type": "string",
              "description": "Vertical text placement: topMiddle, middle or bottomMiddle. Horizontal text alignment belongs to title.align/subtitle.align. Older side anchors are accepted and normalised to the corresponding vertical position.",
              "enum": [
                "topMiddle",
                "middle",
                "bottomMiddle"
              ]
            }
          },
          "required": [
            "x",
            "y",
            "width",
            "height",
            "units",
            "anchor"
          ],
          "additionalProperties": false
        },
        "rotation": {
          "type": "number",
          "description": "Rotation in degrees, not radians; perspective is a device frame variant, not arbitrary 3D.",
          "minimum": -359,
          "maximum": 359
        },
        "opacity": {
          "type": "integer",
          "description": "Element opacity percentage. 0 is transparent and 100 is fully opaque. AppScreens stores 100 as its native null/default, but this document always exposes the effective percentage.",
          "minimum": 0,
          "maximum": 100
        },
        "title": {
          "type": "object",
          "description": "Existing native title/subtitle block. Only exported properties are editable. Native inline gradient/highlight and unsupported ops remain unchanged. Fonts are names from the page or list_fonts, without source URLs.",
          "properties": {
            "runs": {
              "type": "array",
              "description": "Existing rich runs, same number/order; text, bold/italic/underline and colour can change.",
              "items": {
                "type": "object",
                "description": "Literal native text run, including intentional newlines. Existing run count/order stays fixed so unrepresented inline formatting is preserved. No HTML, embeds, Quill commands or automatic terminal newline conversion.",
                "properties": {
                  "text": {
                    "type": "string",
                    "description": "Literal Unicode text, never HTML. A title or subtitle has at most 250 characters across all runs, excluding its final Quill newline.",
                    "maxLength": 251
                  },
                  "bold": {
                    "type": "boolean",
                    "description": "Inline bold."
                  },
                  "italic": {
                    "type": "boolean",
                    "description": "Inline italic."
                  },
                  "underline": {
                    "type": "boolean",
                    "description": "Inline underline."
                  },
                  "color": {
                    "anyOf": [
                      {
                        "type": "object",
                        "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                        "properties": {
                          "rgba": {
                            "type": "array",
                            "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                            "items": {
                              "type": "number",
                              "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                              "minimum": 0,
                              "maximum": 255
                            },
                            "maxItems": 4,
                            "minItems": 4
                          }
                        },
                        "required": [
                          "rgba"
                        ],
                        "additionalProperties": false
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Inline solid colour of this run; null uses the block colour. Omitted when the run has a gradient or other native paint, which stays unchanged."
                  }
                },
                "required": [
                  "text",
                  "bold",
                  "italic",
                  "underline"
                ],
                "additionalProperties": false
              },
              "maxItems": 500,
              "minItems": 0
            },
            "font": {
              "type": "string",
              "description": "Font family name: one already on the page, or a Google or account font from list_fonts. Never a font URL. Text with global true follows the project font and can't take its own, as in the editor: send global: false with the font.",
              "maxLength": 200
            },
            "global": {
              "type": "boolean",
              "description": "Follow the project's title or subtitle font (set in project settings). When true, font is this text's own font, used again if global is turned off."
            },
            "maxFontSize": {
              "type": "number",
              "description": "Fraction of full canvas width. Effective only when fontSizeLock is false, which takes the block out of the matched set size. May be supplied when a locked baseline omitted this native setting.",
              "minimum": 0.005,
              "maximum": 1
            },
            "fontSizeLock": {
              "type": "boolean",
              "description": "Match text size (recommended, the template default): true gives every matched caption the size of the smallest one that fits, per language and output size, so the set stays consistent. False enables maxFontSize for this block only."
            },
            "multiline": {
              "type": "boolean",
              "description": "Allow native multiline layout."
            },
            "align": {
              "type": "string",
              "description": "Block alignment, not an inline operation.",
              "enum": [
                "left",
                "right",
                "center"
              ]
            },
            "color": {
              "anyOf": [
                {
                  "type": "object",
                  "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                  "properties": {
                    "rgba": {
                      "type": "array",
                      "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                      "items": {
                        "type": "number",
                        "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                        "minimum": 0,
                        "maximum": 255
                      },
                      "maxItems": 4,
                      "minItems": 4
                    }
                  },
                  "required": [
                    "rgba"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "null"
                }
              ],
              "description": "Opaque or visible solid text colour. Changed null/alpha-zero is rejected because native serialization restores its default instead of preserving transparency."
            },
            "lineHeight": {
              "type": "number",
              "description": "Native line-height multiplier.",
              "minimum": 0.01,
              "maximum": 3
            },
            "letterSpacing": {
              "type": "number",
              "description": "Native fraction of font size, not pixels.",
              "minimum": 0,
              "maximum": 0.25
            },
            "highlightPaddingX": {
              "type": "number",
              "description": "Fraction of font size.",
              "minimum": 0,
              "maximum": 1
            },
            "highlightPaddingY": {
              "anyOf": [
                {
                  "type": "number",
                  "description": "Fraction of font size. Null inherits X.",
                  "minimum": 0,
                  "maximum": 1
                },
                {
                  "type": "null"
                }
              ],
              "description": "Fraction of font size. Null inherits X."
            },
            "highlightRounding": {
              "type": "number",
              "description": "Fraction of highlight height.",
              "minimum": 0,
              "maximum": 0.5
            },
            "shadow": {
              "type": "object",
              "description": "Native relative shadow. Rendering scales offsets/blur by 0.04 times its reference size, normally full canvas height, NOT pixels. Color null with global false disables the shadow; shadow null itself resets native defaults. Inherited shadows are preserved.",
              "properties": {
                "color": {
                  "anyOf": [
                    {
                      "type": "object",
                      "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                      "properties": {
                        "rgba": {
                          "type": "array",
                          "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                          "items": {
                            "type": "number",
                            "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                            "minimum": 0,
                            "maximum": 255
                          },
                          "maxItems": 4,
                          "minItems": 4
                        }
                      },
                      "required": [
                        "rgba"
                      ],
                      "additionalProperties": false
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA."
                },
                "x": {
                  "type": "number",
                  "description": "Native horizontal offset. 0.125 is 0.5% of reference size.",
                  "minimum": -0.86,
                  "maximum": 0.86
                },
                "y": {
                  "type": "number",
                  "description": "Native vertical offset.",
                  "minimum": -0.86,
                  "maximum": 0.86
                },
                "blur": {
                  "type": "number",
                  "description": "Native blur; 0.25 is 1% of reference size.",
                  "minimum": 0,
                  "maximum": 2.5
                },
                "global": {
                  "type": "boolean",
                  "description": "True inherits the project shadow. False uses this explicit shadow."
                }
              },
              "required": [
                "color",
                "x",
                "y",
                "blur",
                "global"
              ],
              "additionalProperties": false
            }
          },
          "required": [],
          "additionalProperties": false
        },
        "subtitle": {
          "anyOf": [
            {
              "type": "object",
              "description": "Existing native title/subtitle block. Only exported properties are editable. Native inline gradient/highlight and unsupported ops remain unchanged. Fonts are names from the page or list_fonts, without source URLs.",
              "properties": {
                "runs": {
                  "type": "array",
                  "description": "Existing rich runs, same number/order; text, bold/italic/underline and colour can change.",
                  "items": {
                    "type": "object",
                    "description": "Literal native text run, including intentional newlines. Existing run count/order stays fixed so unrepresented inline formatting is preserved. No HTML, embeds, Quill commands or automatic terminal newline conversion.",
                    "properties": {
                      "text": {
                        "type": "string",
                        "description": "Literal Unicode text, never HTML. A title or subtitle has at most 250 characters across all runs, excluding its final Quill newline.",
                        "maxLength": 251
                      },
                      "bold": {
                        "type": "boolean",
                        "description": "Inline bold."
                      },
                      "italic": {
                        "type": "boolean",
                        "description": "Inline italic."
                      },
                      "underline": {
                        "type": "boolean",
                        "description": "Inline underline."
                      },
                      "color": {
                        "anyOf": [
                          {
                            "type": "object",
                            "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                            "properties": {
                              "rgba": {
                                "type": "array",
                                "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                                "items": {
                                  "type": "number",
                                  "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                  "minimum": 0,
                                  "maximum": 255
                                },
                                "maxItems": 4,
                                "minItems": 4
                              }
                            },
                            "required": [
                              "rgba"
                            ],
                            "additionalProperties": false
                          },
                          {
                            "type": "null"
                          }
                        ],
                        "description": "Inline solid colour of this run; null uses the block colour. Omitted when the run has a gradient or other native paint, which stays unchanged."
                      }
                    },
                    "required": [
                      "text",
                      "bold",
                      "italic",
                      "underline"
                    ],
                    "additionalProperties": false
                  },
                  "maxItems": 500,
                  "minItems": 0
                },
                "font": {
                  "type": "string",
                  "description": "Font family name: one already on the page, or a Google or account font from list_fonts. Never a font URL. Text with global true follows the project font and can't take its own, as in the editor: send global: false with the font.",
                  "maxLength": 200
                },
                "global": {
                  "type": "boolean",
                  "description": "Follow the project's title or subtitle font (set in project settings). When true, font is this text's own font, used again if global is turned off."
                },
                "maxFontSize": {
                  "type": "number",
                  "description": "Fraction of full canvas width. Effective only when fontSizeLock is false, which takes the block out of the matched set size. May be supplied when a locked baseline omitted this native setting.",
                  "minimum": 0.005,
                  "maximum": 1
                },
                "fontSizeLock": {
                  "type": "boolean",
                  "description": "Match text size (recommended, the template default): true gives every matched caption the size of the smallest one that fits, per language and output size, so the set stays consistent. False enables maxFontSize for this block only."
                },
                "multiline": {
                  "type": "boolean",
                  "description": "Allow native multiline layout."
                },
                "align": {
                  "type": "string",
                  "description": "Block alignment, not an inline operation.",
                  "enum": [
                    "left",
                    "right",
                    "center"
                  ]
                },
                "color": {
                  "anyOf": [
                    {
                      "type": "object",
                      "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                      "properties": {
                        "rgba": {
                          "type": "array",
                          "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                          "items": {
                            "type": "number",
                            "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                            "minimum": 0,
                            "maximum": 255
                          },
                          "maxItems": 4,
                          "minItems": 4
                        }
                      },
                      "required": [
                        "rgba"
                      ],
                      "additionalProperties": false
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "Opaque or visible solid text colour. Changed null/alpha-zero is rejected because native serialization restores its default instead of preserving transparency."
                },
                "lineHeight": {
                  "type": "number",
                  "description": "Native line-height multiplier.",
                  "minimum": 0.01,
                  "maximum": 3
                },
                "letterSpacing": {
                  "type": "number",
                  "description": "Native fraction of font size, not pixels.",
                  "minimum": 0,
                  "maximum": 0.25
                },
                "highlightPaddingX": {
                  "type": "number",
                  "description": "Fraction of font size.",
                  "minimum": 0,
                  "maximum": 1
                },
                "highlightPaddingY": {
                  "anyOf": [
                    {
                      "type": "number",
                      "description": "Fraction of font size. Null inherits X.",
                      "minimum": 0,
                      "maximum": 1
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "Fraction of font size. Null inherits X."
                },
                "highlightRounding": {
                  "type": "number",
                  "description": "Fraction of highlight height.",
                  "minimum": 0,
                  "maximum": 0.5
                },
                "shadow": {
                  "type": "object",
                  "description": "Native relative shadow. Rendering scales offsets/blur by 0.04 times its reference size, normally full canvas height, NOT pixels. Color null with global false disables the shadow; shadow null itself resets native defaults. Inherited shadows are preserved.",
                  "properties": {
                    "color": {
                      "anyOf": [
                        {
                          "type": "object",
                          "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                          "properties": {
                            "rgba": {
                              "type": "array",
                              "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                              "items": {
                                "type": "number",
                                "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                "minimum": 0,
                                "maximum": 255
                              },
                              "maxItems": 4,
                              "minItems": 4
                            }
                          },
                          "required": [
                            "rgba"
                          ],
                          "additionalProperties": false
                        },
                        {
                          "type": "null"
                        }
                      ],
                      "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA."
                    },
                    "x": {
                      "type": "number",
                      "description": "Native horizontal offset. 0.125 is 0.5% of reference size.",
                      "minimum": -0.86,
                      "maximum": 0.86
                    },
                    "y": {
                      "type": "number",
                      "description": "Native vertical offset.",
                      "minimum": -0.86,
                      "maximum": 0.86
                    },
                    "blur": {
                      "type": "number",
                      "description": "Native blur; 0.25 is 1% of reference size.",
                      "minimum": 0,
                      "maximum": 2.5
                    },
                    "global": {
                      "type": "boolean",
                      "description": "True inherits the project shadow. False uses this explicit shadow."
                    }
                  },
                  "required": [
                    "color",
                    "x",
                    "y",
                    "blur",
                    "global"
                  ],
                  "additionalProperties": false
                }
              },
              "required": [],
              "additionalProperties": false
            },
            {
              "type": "null"
            }
          ],
          "description": "Existing native title/subtitle block. Only exported properties are editable. Native inline gradient/highlight and unsupported ops remain unchanged. Fonts are names from the page or list_fonts, without source URLs."
        },
        "spacing": {
          "type": "number",
          "description": "Gap as fraction of fitted title/subtitle group height.",
          "minimum": 0,
          "maximum": 1
        },
        "titleRatio": {
          "type": "number",
          "description": "Title share of group height; at most 0.99 with a subtitle, 1 is valid without a subtitle.",
          "minimum": 0,
          "maximum": 1
        },
        "decoration": {
          "type": "string",
          "description": "The editor's text decoration. Use laurels for award captions, geometric styles for labels and speech bubbles for quotes. Start with laurelCompactTight for a short award caption. Choose a wider compact style if the caption needs more room. Use none to clear the decoration. Use only verified award and rating claims.",
          "enum": [
            "none",
            "laurelCompactSquare",
            "laurelCompactTight",
            "laurelCompactWide",
            "laurelCompactWider",
            "laurelTight",
            "laurelWide",
            "laurelWider",
            "rectangle",
            "rectangleRounded",
            "ovalRounded",
            "square",
            "squareRounded",
            "circle",
            "badge",
            "commentLeft",
            "commentRight",
            "chatBubbleLeft",
            "chatBubbleRight",
            "starBackground"
          ]
        },
        "decorationFill": {
          "anyOf": [
            {
              "anyOf": [
                {
                  "type": "object",
                  "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                  "properties": {
                    "rgba": {
                      "type": "array",
                      "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                      "items": {
                        "type": "number",
                        "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                        "minimum": 0,
                        "maximum": 255
                      },
                      "maxItems": 4,
                      "minItems": 4
                    }
                  },
                  "required": [
                    "rgba"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "description": "Gradient paint.",
                  "properties": {
                    "gradient": {
                      "type": "object",
                      "description": "Two-colour gradient, as the editor's gradient picker makes it.",
                      "properties": {
                        "style": {
                          "type": "string",
                          "description": "linear, or radial from the centre point.",
                          "enum": [
                            "linear",
                            "radial"
                          ]
                        },
                        "angle": {
                          "type": "number",
                          "description": "Linear: angle in degrees. Radial: radius as a percentage (1..100), centred in the painted area.",
                          "minimum": -360,
                          "maximum": 360
                        },
                        "from": {
                          "type": "object",
                          "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                          "properties": {
                            "rgba": {
                              "type": "array",
                              "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                              "items": {
                                "type": "number",
                                "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                "minimum": 0,
                                "maximum": 255
                              },
                              "maxItems": 4,
                              "minItems": 4
                            }
                          },
                          "required": [
                            "rgba"
                          ],
                          "additionalProperties": false
                        },
                        "to": {
                          "type": "object",
                          "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                          "properties": {
                            "rgba": {
                              "type": "array",
                              "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                              "items": {
                                "type": "number",
                                "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                "minimum": 0,
                                "maximum": 255
                              },
                              "maxItems": 4,
                              "minItems": 4
                            }
                          },
                          "required": [
                            "rgba"
                          ],
                          "additionalProperties": false
                        },
                        "stopFrom": {
                          "type": "number",
                          "description": "Where the first colour stops, 0..1.",
                          "minimum": 0,
                          "maximum": 1
                        },
                        "stopTo": {
                          "type": "number",
                          "description": "Where the second colour starts, 0..1.",
                          "minimum": 0,
                          "maximum": 1
                        }
                      },
                      "required": [
                        "style",
                        "angle",
                        "from",
                        "to",
                        "stopFrom",
                        "stopTo"
                      ],
                      "additionalProperties": false
                    }
                  },
                  "required": [
                    "gradient"
                  ],
                  "additionalProperties": false
                }
              ],
              "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
            },
            {
              "type": "null"
            }
          ],
          "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
        },
        "decorationStroke": {
          "anyOf": [
            {
              "anyOf": [
                {
                  "type": "object",
                  "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                  "properties": {
                    "rgba": {
                      "type": "array",
                      "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                      "items": {
                        "type": "number",
                        "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                        "minimum": 0,
                        "maximum": 255
                      },
                      "maxItems": 4,
                      "minItems": 4
                    }
                  },
                  "required": [
                    "rgba"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "description": "Gradient paint.",
                  "properties": {
                    "gradient": {
                      "type": "object",
                      "description": "Two-colour gradient, as the editor's gradient picker makes it.",
                      "properties": {
                        "style": {
                          "type": "string",
                          "description": "linear, or radial from the centre point.",
                          "enum": [
                            "linear",
                            "radial"
                          ]
                        },
                        "angle": {
                          "type": "number",
                          "description": "Linear: angle in degrees. Radial: radius as a percentage (1..100), centred in the painted area.",
                          "minimum": -360,
                          "maximum": 360
                        },
                        "from": {
                          "type": "object",
                          "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                          "properties": {
                            "rgba": {
                              "type": "array",
                              "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                              "items": {
                                "type": "number",
                                "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                "minimum": 0,
                                "maximum": 255
                              },
                              "maxItems": 4,
                              "minItems": 4
                            }
                          },
                          "required": [
                            "rgba"
                          ],
                          "additionalProperties": false
                        },
                        "to": {
                          "type": "object",
                          "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                          "properties": {
                            "rgba": {
                              "type": "array",
                              "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                              "items": {
                                "type": "number",
                                "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                "minimum": 0,
                                "maximum": 255
                              },
                              "maxItems": 4,
                              "minItems": 4
                            }
                          },
                          "required": [
                            "rgba"
                          ],
                          "additionalProperties": false
                        },
                        "stopFrom": {
                          "type": "number",
                          "description": "Where the first colour stops, 0..1.",
                          "minimum": 0,
                          "maximum": 1
                        },
                        "stopTo": {
                          "type": "number",
                          "description": "Where the second colour starts, 0..1.",
                          "minimum": 0,
                          "maximum": 1
                        }
                      },
                      "required": [
                        "style",
                        "angle",
                        "from",
                        "to",
                        "stopFrom",
                        "stopTo"
                      ],
                      "additionalProperties": false
                    }
                  },
                  "required": [
                    "gradient"
                  ],
                  "additionalProperties": false
                }
              ],
              "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
            },
            {
              "type": "null"
            }
          ],
          "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
        },
        "decorationStrokeWidth": {
          "type": "number",
          "description": "Fraction of decoration image height, not pixels. 0.01 is 1%.",
          "minimum": 0,
          "maximum": 0.2
        },
        "decorationShadow": {
          "type": "object",
          "description": "Native relative shadow. Rendering scales offsets/blur by 0.04 times its reference size, normally full canvas height, NOT pixels. Color null with global false disables the shadow; shadow null itself resets native defaults. Inherited shadows are preserved.",
          "properties": {
            "color": {
              "anyOf": [
                {
                  "type": "object",
                  "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                  "properties": {
                    "rgba": {
                      "type": "array",
                      "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                      "items": {
                        "type": "number",
                        "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                        "minimum": 0,
                        "maximum": 255
                      },
                      "maxItems": 4,
                      "minItems": 4
                    }
                  },
                  "required": [
                    "rgba"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "null"
                }
              ],
              "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA."
            },
            "x": {
              "type": "number",
              "description": "Native horizontal offset. 0.125 is 0.5% of reference size.",
              "minimum": -0.86,
              "maximum": 0.86
            },
            "y": {
              "type": "number",
              "description": "Native vertical offset.",
              "minimum": -0.86,
              "maximum": 0.86
            },
            "blur": {
              "type": "number",
              "description": "Native blur; 0.25 is 1% of reference size.",
              "minimum": 0,
              "maximum": 2.5
            },
            "global": {
              "type": "boolean",
              "description": "True inherits the project shadow. False uses this explicit shadow."
            }
          },
          "required": [
            "color",
            "x",
            "y",
            "blur",
            "global"
          ],
          "additionalProperties": false
        }
      },
      "required": [
        "type",
        "id",
        "layer",
        "opacity"
      ],
      "additionalProperties": false
    },
    "shape": {
      "type": "object",
      "description": "Editable native geometry and paint. Fill and stroke can be solid or a gradient.",
      "properties": {
        "type": {
          "type": "string",
          "description": "Component type.",
          "enum": [
            "shape"
          ]
        },
        "id": {
          "type": "string",
          "description": "Existing saved native UID. It is not an array index or an AI-generated identity.",
          "maxLength": 128,
          "minLength": 8,
          "pattern": "^[A-Za-z0-9_-]{8,128}$"
        },
        "layer": {
          "type": "integer",
          "description": "Native layer, zero is bottom. Each layer is a vertical stack, as in the editor: array order is the stack order, the first element's y is the top of the stack and each later element starts where the one above ends (its y is derived). Put elements that should overlap or sit freely in separate layers. Empty layers are removed.",
          "minimum": 0,
          "maximum": 14
        },
        "location": {
          "type": "object",
          "description": "Native rectangle. In % mode 0.5 is half the canvas, NOT 50; x/y range -5..5, width/height 0..5. In px mode x/y range -100000..100000, width/height 0..100000. x/y locate the rectangle; anchor does not shift its origin.",
          "properties": {
            "x": {
              "type": "number",
              "description": "Rectangle X. Bounds depend on units.",
              "minimum": -100000,
              "maximum": 100000
            },
            "y": {
              "type": "number",
              "description": "Rectangle Y.",
              "minimum": -100000,
              "maximum": 100000
            },
            "width": {
              "type": "number",
              "description": "Rectangle width; zero-size existing objects are valid.",
              "minimum": 0,
              "maximum": 100000
            },
            "height": {
              "type": "number",
              "description": "Rectangle height.",
              "minimum": 0,
              "maximum": 100000
            },
            "units": {
              "type": "string",
              "description": "Native % fractions or px. Values are not converted when changing units.",
              "enum": [
                "px",
                "%"
              ]
            },
            "anchor": {
              "type": "string",
              "description": "Text uses this for vertical placement. For images, devices and shapes this legacy field is preserved but does not position content; use position instead.",
              "enum": [
                "topMiddle",
                "topLeft",
                "topRight",
                "middle",
                "middleLeft",
                "middleRight",
                "bottomMiddle",
                "bottomLeft",
                "bottomRight"
              ]
            }
          },
          "required": [
            "x",
            "y",
            "width",
            "height",
            "units",
            "anchor"
          ],
          "additionalProperties": false
        },
        "rotation": {
          "type": "number",
          "description": "Rotation in degrees, not radians; perspective is a device frame variant, not arbitrary 3D.",
          "minimum": -359,
          "maximum": 359
        },
        "opacity": {
          "type": "integer",
          "description": "Element opacity percentage. 0 is transparent and 100 is fully opaque. AppScreens stores 100 as its native null/default, but this document always exposes the effective percentage.",
          "minimum": 0,
          "maximum": 100
        },
        "shadow": {
          "type": "object",
          "description": "Native relative shadow. Rendering scales offsets/blur by 0.04 times its reference size, normally full canvas height, NOT pixels. Color null with global false disables the shadow; shadow null itself resets native defaults. Inherited shadows are preserved.",
          "properties": {
            "color": {
              "anyOf": [
                {
                  "type": "object",
                  "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                  "properties": {
                    "rgba": {
                      "type": "array",
                      "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                      "items": {
                        "type": "number",
                        "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                        "minimum": 0,
                        "maximum": 255
                      },
                      "maxItems": 4,
                      "minItems": 4
                    }
                  },
                  "required": [
                    "rgba"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "null"
                }
              ],
              "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA."
            },
            "x": {
              "type": "number",
              "description": "Native horizontal offset. 0.125 is 0.5% of reference size.",
              "minimum": -0.86,
              "maximum": 0.86
            },
            "y": {
              "type": "number",
              "description": "Native vertical offset.",
              "minimum": -0.86,
              "maximum": 0.86
            },
            "blur": {
              "type": "number",
              "description": "Native blur; 0.25 is 1% of reference size.",
              "minimum": 0,
              "maximum": 2.5
            },
            "global": {
              "type": "boolean",
              "description": "True inherits the project shadow. False uses this explicit shadow."
            }
          },
          "required": [
            "color",
            "x",
            "y",
            "blur",
            "global"
          ],
          "additionalProperties": false
        },
        "shape": {
          "type": "string",
          "description": "Native shape.",
          "enum": [
            "rectangle",
            "square",
            "circle",
            "ellipse",
            "triangle",
            "line"
          ]
        },
        "fit": {
          "type": "string",
          "description": "Native shape sizing mode, including fill.",
          "enum": [
            "fill",
            "contain",
            "covertop",
            "coverbottom",
            "covercenter"
          ]
        },
        "lineDirection": {
          "type": "string",
          "description": "Line shapes only.",
          "enum": [
            "horizontal",
            "vertical"
          ]
        },
        "position": {
          "type": "string",
          "description": "Content anchor. Horizontal lines use topMiddle/middle/bottomMiddle; vertical lines use middleLeft/middle/middleRight. Other saved line anchors render at the centre.",
          "enum": [
            "topMiddle",
            "topLeft",
            "topRight",
            "middle",
            "middleLeft",
            "middleRight",
            "bottomMiddle",
            "bottomLeft",
            "bottomRight"
          ]
        },
        "boundary": {
          "type": "string",
          "description": "How rotation meets the box. inside (the default): the rotated content is scaled down until its rotated bounds fit the unrotated box, so a tilted wide image draws smaller, by min(W / (w cos a + h sin a), H / (h cos a + w sin a)) for content w x h in box W x H. outside: the box itself turns and the content keeps its size, so its corners can pass the box. Use outside to tilt a card without shrinking it.",
          "enum": [
            "inside",
            "outside"
          ]
        },
        "fill": {
          "anyOf": [
            {
              "anyOf": [
                {
                  "type": "object",
                  "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                  "properties": {
                    "rgba": {
                      "type": "array",
                      "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                      "items": {
                        "type": "number",
                        "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                        "minimum": 0,
                        "maximum": 255
                      },
                      "maxItems": 4,
                      "minItems": 4
                    }
                  },
                  "required": [
                    "rgba"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "description": "Gradient paint.",
                  "properties": {
                    "gradient": {
                      "type": "object",
                      "description": "Two-colour gradient, as the editor's gradient picker makes it.",
                      "properties": {
                        "style": {
                          "type": "string",
                          "description": "linear, or radial from the centre point.",
                          "enum": [
                            "linear",
                            "radial"
                          ]
                        },
                        "angle": {
                          "type": "number",
                          "description": "Linear: angle in degrees. Radial: radius as a percentage (1..100), centred in the painted area.",
                          "minimum": -360,
                          "maximum": 360
                        },
                        "from": {
                          "type": "object",
                          "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                          "properties": {
                            "rgba": {
                              "type": "array",
                              "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                              "items": {
                                "type": "number",
                                "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                "minimum": 0,
                                "maximum": 255
                              },
                              "maxItems": 4,
                              "minItems": 4
                            }
                          },
                          "required": [
                            "rgba"
                          ],
                          "additionalProperties": false
                        },
                        "to": {
                          "type": "object",
                          "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                          "properties": {
                            "rgba": {
                              "type": "array",
                              "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                              "items": {
                                "type": "number",
                                "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                "minimum": 0,
                                "maximum": 255
                              },
                              "maxItems": 4,
                              "minItems": 4
                            }
                          },
                          "required": [
                            "rgba"
                          ],
                          "additionalProperties": false
                        },
                        "stopFrom": {
                          "type": "number",
                          "description": "Where the first colour stops, 0..1.",
                          "minimum": 0,
                          "maximum": 1
                        },
                        "stopTo": {
                          "type": "number",
                          "description": "Where the second colour starts, 0..1.",
                          "minimum": 0,
                          "maximum": 1
                        }
                      },
                      "required": [
                        "style",
                        "angle",
                        "from",
                        "to",
                        "stopFrom",
                        "stopTo"
                      ],
                      "additionalProperties": false
                    }
                  },
                  "required": [
                    "gradient"
                  ],
                  "additionalProperties": false
                }
              ],
              "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
            },
            {
              "type": "null"
            }
          ],
          "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
        },
        "stroke": {
          "anyOf": [
            {
              "anyOf": [
                {
                  "type": "object",
                  "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                  "properties": {
                    "rgba": {
                      "type": "array",
                      "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                      "items": {
                        "type": "number",
                        "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                        "minimum": 0,
                        "maximum": 255
                      },
                      "maxItems": 4,
                      "minItems": 4
                    }
                  },
                  "required": [
                    "rgba"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "description": "Gradient paint.",
                  "properties": {
                    "gradient": {
                      "type": "object",
                      "description": "Two-colour gradient, as the editor's gradient picker makes it.",
                      "properties": {
                        "style": {
                          "type": "string",
                          "description": "linear, or radial from the centre point.",
                          "enum": [
                            "linear",
                            "radial"
                          ]
                        },
                        "angle": {
                          "type": "number",
                          "description": "Linear: angle in degrees. Radial: radius as a percentage (1..100), centred in the painted area.",
                          "minimum": -360,
                          "maximum": 360
                        },
                        "from": {
                          "type": "object",
                          "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                          "properties": {
                            "rgba": {
                              "type": "array",
                              "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                              "items": {
                                "type": "number",
                                "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                "minimum": 0,
                                "maximum": 255
                              },
                              "maxItems": 4,
                              "minItems": 4
                            }
                          },
                          "required": [
                            "rgba"
                          ],
                          "additionalProperties": false
                        },
                        "to": {
                          "type": "object",
                          "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                          "properties": {
                            "rgba": {
                              "type": "array",
                              "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                              "items": {
                                "type": "number",
                                "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                "minimum": 0,
                                "maximum": 255
                              },
                              "maxItems": 4,
                              "minItems": 4
                            }
                          },
                          "required": [
                            "rgba"
                          ],
                          "additionalProperties": false
                        },
                        "stopFrom": {
                          "type": "number",
                          "description": "Where the first colour stops, 0..1.",
                          "minimum": 0,
                          "maximum": 1
                        },
                        "stopTo": {
                          "type": "number",
                          "description": "Where the second colour starts, 0..1.",
                          "minimum": 0,
                          "maximum": 1
                        }
                      },
                      "required": [
                        "style",
                        "angle",
                        "from",
                        "to",
                        "stopFrom",
                        "stopTo"
                      ],
                      "additionalProperties": false
                    }
                  },
                  "required": [
                    "gradient"
                  ],
                  "additionalProperties": false
                }
              ],
              "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
            },
            {
              "type": "null"
            }
          ],
          "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
        },
        "strokeWidth": {
          "type": "number",
          "description": "PERCENT; 2 means 2%, not 0.02. Of the shortest rendered edge, except a line with lineStrokeCanvas true: of canvas height, capped to the line box thickness.",
          "minimum": 0,
          "maximum": 100
        },
        "lineStrokeCanvas": {
          "type": "boolean",
          "description": "Line shapes only. True keeps strokeWidth a percent of canvas height, so resizing the box does not change it. False or unset is the legacy shortest-edge stroke. New editor lines use true."
        },
        "cornerRadius": {
          "type": "number",
          "description": "PERCENT of shortest rendered edge.",
          "minimum": 0,
          "maximum": 50
        }
      },
      "required": [
        "type",
        "id",
        "layer",
        "opacity"
      ],
      "additionalProperties": false
    },
    "image": {
      "type": "object",
      "description": "Native image overlay. Asset pixels and SVG path geometry remain native-owned. Source slots, SVG colour/stroke styling and the frame (corner rounding, border, fill, padding) are editable. Fill shows behind transparent pixels and around a padded image.",
      "properties": {
        "type": {
          "type": "string",
          "description": "Component type.",
          "enum": [
            "image"
          ]
        },
        "id": {
          "type": "string",
          "description": "Existing saved native UID. It is not an array index or an AI-generated identity.",
          "maxLength": 128,
          "minLength": 8,
          "pattern": "^[A-Za-z0-9_-]{8,128}$"
        },
        "layer": {
          "type": "integer",
          "description": "Native layer, zero is bottom. Each layer is a vertical stack, as in the editor: array order is the stack order, the first element's y is the top of the stack and each later element starts where the one above ends (its y is derived). Put elements that should overlap or sit freely in separate layers. Empty layers are removed.",
          "minimum": 0,
          "maximum": 14
        },
        "location": {
          "type": "object",
          "description": "Native rectangle. In % mode 0.5 is half the canvas, NOT 50; x/y range -5..5, width/height 0..5. In px mode x/y range -100000..100000, width/height 0..100000. x/y locate the rectangle; anchor does not shift its origin.",
          "properties": {
            "x": {
              "type": "number",
              "description": "Rectangle X. Bounds depend on units.",
              "minimum": -100000,
              "maximum": 100000
            },
            "y": {
              "type": "number",
              "description": "Rectangle Y.",
              "minimum": -100000,
              "maximum": 100000
            },
            "width": {
              "type": "number",
              "description": "Rectangle width; zero-size existing objects are valid.",
              "minimum": 0,
              "maximum": 100000
            },
            "height": {
              "type": "number",
              "description": "Rectangle height.",
              "minimum": 0,
              "maximum": 100000
            },
            "units": {
              "type": "string",
              "description": "Native % fractions or px. Values are not converted when changing units.",
              "enum": [
                "px",
                "%"
              ]
            },
            "anchor": {
              "type": "string",
              "description": "Text uses this for vertical placement. For images, devices and shapes this legacy field is preserved but does not position content; use position instead.",
              "enum": [
                "topMiddle",
                "topLeft",
                "topRight",
                "middle",
                "middleLeft",
                "middleRight",
                "bottomMiddle",
                "bottomLeft",
                "bottomRight"
              ]
            }
          },
          "required": [
            "x",
            "y",
            "width",
            "height",
            "units",
            "anchor"
          ],
          "additionalProperties": false
        },
        "rotation": {
          "type": "number",
          "description": "Rotation in degrees, not radians; perspective is a device frame variant, not arbitrary 3D.",
          "minimum": -359,
          "maximum": 359
        },
        "opacity": {
          "type": "integer",
          "description": "Element opacity percentage. 0 is transparent and 100 is fully opaque. AppScreens stores 100 as its native null/default, but this document always exposes the effective percentage.",
          "minimum": 0,
          "maximum": 100
        },
        "slots": {
          "type": "array",
          "description": "Only existing explicit source assignments. Empty slots/fallbacks are not materialized. Each field/language/target combination must remain present and unchanged; only assetId can change.",
          "items": {
            "type": "object",
            "description": "One source assignment.",
            "properties": {
              "field": {
                "type": "string",
                "description": "Original storage provenance.",
                "enum": [
                  "base",
                  "translation",
                  "legacy"
                ]
              },
              "language": {
                "type": "string",
                "description": "An existing language or target key. It cannot create languages or targets.",
                "maxLength": 128,
                "minLength": 1,
                "pattern": "^[A-Za-z0-9_-]{1,128}$"
              },
              "targetId": {
                "type": "string",
                "description": "An existing language or target key. It cannot create languages or targets.",
                "maxLength": 128,
                "minLength": 1,
                "pattern": "^[A-Za-z0-9_-]{1,128}$"
              },
              "assetId": {
                "type": "string",
                "description": "Approved stable asset ID. Never a URL, data URI, signed URL or token.",
                "maxLength": 1024,
                "minLength": 1
              }
            },
            "required": [
              "field",
              "language",
              "targetId",
              "assetId"
            ],
            "additionalProperties": false
          },
          "maxItems": 500,
          "minItems": 0
        },
        "fit": {
          "type": "string",
          "description": "Native contain or width-cover alignment. There is no cover/fill image mode.",
          "enum": [
            "contain",
            "covertop",
            "coverbottom",
            "covercenter"
          ]
        },
        "position": {
          "type": "string",
          "description": "Fitted source anchor.",
          "enum": [
            "topMiddle",
            "topLeft",
            "topRight",
            "middle",
            "middleLeft",
            "middleRight",
            "bottomMiddle",
            "bottomLeft",
            "bottomRight"
          ]
        },
        "boundary": {
          "type": "string",
          "description": "How rotation meets the box. inside (the default): the rotated content is scaled down until its rotated bounds fit the unrotated box, so a tilted wide image draws smaller, by min(W / (w cos a + h sin a), H / (h cos a + w sin a)) for content w x h in box W x H. outside: the box itself turns and the content keeps its size, so its corners can pass the box. Use outside to tilt a card without shrinking it.",
          "enum": [
            "inside",
            "outside"
          ]
        },
        "shadow": {
          "type": "object",
          "description": "Native relative shadow. Rendering scales offsets/blur by 0.04 times its reference size, normally full canvas height, NOT pixels. Color null with global false disables the shadow; shadow null itself resets native defaults. Inherited shadows are preserved.",
          "properties": {
            "color": {
              "anyOf": [
                {
                  "type": "object",
                  "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                  "properties": {
                    "rgba": {
                      "type": "array",
                      "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                      "items": {
                        "type": "number",
                        "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                        "minimum": 0,
                        "maximum": 255
                      },
                      "maxItems": 4,
                      "minItems": 4
                    }
                  },
                  "required": [
                    "rgba"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "null"
                }
              ],
              "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA."
            },
            "x": {
              "type": "number",
              "description": "Native horizontal offset. 0.125 is 0.5% of reference size.",
              "minimum": -0.86,
              "maximum": 0.86
            },
            "y": {
              "type": "number",
              "description": "Native vertical offset.",
              "minimum": -0.86,
              "maximum": 0.86
            },
            "blur": {
              "type": "number",
              "description": "Native blur; 0.25 is 1% of reference size.",
              "minimum": 0,
              "maximum": 2.5
            },
            "global": {
              "type": "boolean",
              "description": "True inherits the project shadow. False uses this explicit shadow."
            }
          },
          "required": [
            "color",
            "x",
            "y",
            "blur",
            "global"
          ],
          "additionalProperties": false
        },
        "svgOverlayColor": {
          "anyOf": [
            {
              "anyOf": [
                {
                  "type": "object",
                  "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                  "properties": {
                    "rgba": {
                      "type": "array",
                      "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                      "items": {
                        "type": "number",
                        "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                        "minimum": 0,
                        "maximum": 255
                      },
                      "maxItems": 4,
                      "minItems": 4
                    }
                  },
                  "required": [
                    "rgba"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "description": "Gradient paint.",
                  "properties": {
                    "gradient": {
                      "type": "object",
                      "description": "Two-colour gradient, as the editor's gradient picker makes it.",
                      "properties": {
                        "style": {
                          "type": "string",
                          "description": "linear, or radial from the centre point.",
                          "enum": [
                            "linear",
                            "radial"
                          ]
                        },
                        "angle": {
                          "type": "number",
                          "description": "Linear: angle in degrees. Radial: radius as a percentage (1..100), centred in the painted area.",
                          "minimum": -360,
                          "maximum": 360
                        },
                        "from": {
                          "type": "object",
                          "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                          "properties": {
                            "rgba": {
                              "type": "array",
                              "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                              "items": {
                                "type": "number",
                                "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                "minimum": 0,
                                "maximum": 255
                              },
                              "maxItems": 4,
                              "minItems": 4
                            }
                          },
                          "required": [
                            "rgba"
                          ],
                          "additionalProperties": false
                        },
                        "to": {
                          "type": "object",
                          "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                          "properties": {
                            "rgba": {
                              "type": "array",
                              "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                              "items": {
                                "type": "number",
                                "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                "minimum": 0,
                                "maximum": 255
                              },
                              "maxItems": 4,
                              "minItems": 4
                            }
                          },
                          "required": [
                            "rgba"
                          ],
                          "additionalProperties": false
                        },
                        "stopFrom": {
                          "type": "number",
                          "description": "Where the first colour stops, 0..1.",
                          "minimum": 0,
                          "maximum": 1
                        },
                        "stopTo": {
                          "type": "number",
                          "description": "Where the second colour starts, 0..1.",
                          "minimum": 0,
                          "maximum": 1
                        }
                      },
                      "required": [
                        "style",
                        "angle",
                        "from",
                        "to",
                        "stopFrom",
                        "stopTo"
                      ],
                      "additionalProperties": false
                    }
                  },
                  "required": [
                    "gradient"
                  ],
                  "additionalProperties": false
                }
              ],
              "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
            },
            {
              "type": "null"
            }
          ],
          "description": "SVG colour overlay, solid or gradient. Recolours existing visible fills and, without an explicit SVG stroke, existing strokes. Null or transparent means keep original artwork colours. No effect on raster images."
        },
        "svgStrokeColor": {
          "anyOf": [
            {
              "anyOf": [
                {
                  "type": "object",
                  "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                  "properties": {
                    "rgba": {
                      "type": "array",
                      "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                      "items": {
                        "type": "number",
                        "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                        "minimum": 0,
                        "maximum": 255
                      },
                      "maxItems": 4,
                      "minItems": 4
                    }
                  },
                  "required": [
                    "rgba"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "description": "Gradient paint.",
                  "properties": {
                    "gradient": {
                      "type": "object",
                      "description": "Two-colour gradient, as the editor's gradient picker makes it.",
                      "properties": {
                        "style": {
                          "type": "string",
                          "description": "linear, or radial from the centre point.",
                          "enum": [
                            "linear",
                            "radial"
                          ]
                        },
                        "angle": {
                          "type": "number",
                          "description": "Linear: angle in degrees. Radial: radius as a percentage (1..100), centred in the painted area.",
                          "minimum": -360,
                          "maximum": 360
                        },
                        "from": {
                          "type": "object",
                          "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                          "properties": {
                            "rgba": {
                              "type": "array",
                              "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                              "items": {
                                "type": "number",
                                "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                "minimum": 0,
                                "maximum": 255
                              },
                              "maxItems": 4,
                              "minItems": 4
                            }
                          },
                          "required": [
                            "rgba"
                          ],
                          "additionalProperties": false
                        },
                        "to": {
                          "type": "object",
                          "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                          "properties": {
                            "rgba": {
                              "type": "array",
                              "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                              "items": {
                                "type": "number",
                                "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                "minimum": 0,
                                "maximum": 255
                              },
                              "maxItems": 4,
                              "minItems": 4
                            }
                          },
                          "required": [
                            "rgba"
                          ],
                          "additionalProperties": false
                        },
                        "stopFrom": {
                          "type": "number",
                          "description": "Where the first colour stops, 0..1.",
                          "minimum": 0,
                          "maximum": 1
                        },
                        "stopTo": {
                          "type": "number",
                          "description": "Where the second colour starts, 0..1.",
                          "minimum": 0,
                          "maximum": 1
                        }
                      },
                      "required": [
                        "style",
                        "angle",
                        "from",
                        "to",
                        "stopFrom",
                        "stopTo"
                      ],
                      "additionalProperties": false
                    }
                  },
                  "required": [
                    "gradient"
                  ],
                  "additionalProperties": false
                }
              ],
              "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
            },
            {
              "type": "null"
            }
          ],
          "description": "SVG path stroke, solid or gradient. Null or transparent keeps the source stroke. Uses svgStrokeWidth, not the image frame borderWidth."
        },
        "svgStrokeWidth": {
          "type": "number",
          "description": "Fraction of full canvas height, as the editor SVG stroke control: 0.01 means 1%. Needs svgStrokeColor. No effect on raster images.",
          "minimum": 0,
          "maximum": 0.2
        },
        "cornerRadius": {
          "type": "number",
          "description": "PERCENT of the shortest visible image edge; 50 is a circle or pill. Rounds the whole frame: fill, border and image follow it, and a padded image rounds by cornerRadius minus padding. Any frame setting clips width-cover overflow to the box.",
          "minimum": 0,
          "maximum": 50
        },
        "border": {
          "anyOf": [
            {
              "anyOf": [
                {
                  "type": "object",
                  "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                  "properties": {
                    "rgba": {
                      "type": "array",
                      "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                      "items": {
                        "type": "number",
                        "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                        "minimum": 0,
                        "maximum": 255
                      },
                      "maxItems": 4,
                      "minItems": 4
                    }
                  },
                  "required": [
                    "rgba"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "description": "Gradient paint.",
                  "properties": {
                    "gradient": {
                      "type": "object",
                      "description": "Two-colour gradient, as the editor's gradient picker makes it.",
                      "properties": {
                        "style": {
                          "type": "string",
                          "description": "linear, or radial from the centre point.",
                          "enum": [
                            "linear",
                            "radial"
                          ]
                        },
                        "angle": {
                          "type": "number",
                          "description": "Linear: angle in degrees. Radial: radius as a percentage (1..100), centred in the painted area.",
                          "minimum": -360,
                          "maximum": 360
                        },
                        "from": {
                          "type": "object",
                          "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                          "properties": {
                            "rgba": {
                              "type": "array",
                              "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                              "items": {
                                "type": "number",
                                "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                "minimum": 0,
                                "maximum": 255
                              },
                              "maxItems": 4,
                              "minItems": 4
                            }
                          },
                          "required": [
                            "rgba"
                          ],
                          "additionalProperties": false
                        },
                        "to": {
                          "type": "object",
                          "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                          "properties": {
                            "rgba": {
                              "type": "array",
                              "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                              "items": {
                                "type": "number",
                                "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                "minimum": 0,
                                "maximum": 255
                              },
                              "maxItems": 4,
                              "minItems": 4
                            }
                          },
                          "required": [
                            "rgba"
                          ],
                          "additionalProperties": false
                        },
                        "stopFrom": {
                          "type": "number",
                          "description": "Where the first colour stops, 0..1.",
                          "minimum": 0,
                          "maximum": 1
                        },
                        "stopTo": {
                          "type": "number",
                          "description": "Where the second colour starts, 0..1.",
                          "minimum": 0,
                          "maximum": 1
                        }
                      },
                      "required": [
                        "style",
                        "angle",
                        "from",
                        "to",
                        "stopFrom",
                        "stopTo"
                      ],
                      "additionalProperties": false
                    }
                  },
                  "required": [
                    "gradient"
                  ],
                  "additionalProperties": false
                }
              ],
              "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
            },
            {
              "type": "null"
            }
          ],
          "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
        },
        "borderWidth": {
          "type": "number",
          "description": "PERCENT; 2 means 2%, not 0.02. Of the shortest visible image edge, drawn inside the image edge. Needs a border paint.",
          "minimum": 0,
          "maximum": 50
        },
        "fill": {
          "anyOf": [
            {
              "anyOf": [
                {
                  "type": "object",
                  "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                  "properties": {
                    "rgba": {
                      "type": "array",
                      "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                      "items": {
                        "type": "number",
                        "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                        "minimum": 0,
                        "maximum": 255
                      },
                      "maxItems": 4,
                      "minItems": 4
                    }
                  },
                  "required": [
                    "rgba"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "description": "Gradient paint.",
                  "properties": {
                    "gradient": {
                      "type": "object",
                      "description": "Two-colour gradient, as the editor's gradient picker makes it.",
                      "properties": {
                        "style": {
                          "type": "string",
                          "description": "linear, or radial from the centre point.",
                          "enum": [
                            "linear",
                            "radial"
                          ]
                        },
                        "angle": {
                          "type": "number",
                          "description": "Linear: angle in degrees. Radial: radius as a percentage (1..100), centred in the painted area.",
                          "minimum": -360,
                          "maximum": 360
                        },
                        "from": {
                          "type": "object",
                          "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                          "properties": {
                            "rgba": {
                              "type": "array",
                              "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                              "items": {
                                "type": "number",
                                "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                "minimum": 0,
                                "maximum": 255
                              },
                              "maxItems": 4,
                              "minItems": 4
                            }
                          },
                          "required": [
                            "rgba"
                          ],
                          "additionalProperties": false
                        },
                        "to": {
                          "type": "object",
                          "description": "Solid RGBA channels. R/G/B are 0..255, alpha 0..1. Input also accepts #RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(), rgba() or transparent; reads return numeric RGBA.",
                          "properties": {
                            "rgba": {
                              "type": "array",
                              "description": "Exactly four channels [red, green, blue, alpha]. RGB must be integers 0..255; alpha 0..1.",
                              "items": {
                                "type": "number",
                                "description": "Channel; RGB integer and alpha maximum 1 are also checked.",
                                "minimum": 0,
                                "maximum": 255
                              },
                              "maxItems": 4,
                              "minItems": 4
                            }
                          },
                          "required": [
                            "rgba"
                          ],
                          "additionalProperties": false
                        },
                        "stopFrom": {
                          "type": "number",
                          "description": "Where the first colour stops, 0..1.",
                          "minimum": 0,
                          "maximum": 1
                        },
                        "stopTo": {
                          "type": "number",
                          "description": "Where the second colour starts, 0..1.",
                          "minimum": 0,
                          "maximum": 1
                        }
                      },
                      "required": [
                        "style",
                        "angle",
                        "from",
                        "to",
                        "stopFrom",
                        "stopTo"
                      ],
                      "additionalProperties": false
                    }
                  },
                  "required": [
                    "gradient"
                  ],
                  "additionalProperties": false
                }
              ],
              "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
            },
            {
              "type": "null"
            }
          ],
          "description": "A solid {rgba} colour or a {gradient}. Solid colours and gradient endpoints also accept hex, rgb() or rgba() strings. Switching between paints is allowed."
        },
        "padding": {
          "type": "number",
          "description": "PERCENT of the shortest visible image edge. Insets the image inside its frame so the fill shows around it; the frame keeps its size.",
          "minimum": 0,
          "maximum": 40
        }
      },
      "required": [
        "type",
        "id",
        "layer",
        "opacity",
        "slots"
      ],
      "additionalProperties": false
    },
    "preserved": {
      "type": "object",
      "description": "An unsupported native object, kept editable in AppScreens. Only layer placement/order can change in this draft; no opaque native properties are returned.",
      "properties": {
        "type": {
          "type": "string",
          "description": "Component type.",
          "enum": [
            "preserved"
          ]
        },
        "id": {
          "type": "string",
          "description": "Existing saved native UID. It is not an array index or an AI-generated identity.",
          "maxLength": 128,
          "minLength": 8,
          "pattern": "^[A-Za-z0-9_-]{8,128}$"
        },
        "layer": {
          "type": "integer",
          "description": "Native layer, zero is bottom. Each layer is a vertical stack, as in the editor: array order is the stack order, the first element's y is the top of the stack and each later element starts where the one above ends (its y is derived). Put elements that should overlap or sit freely in separate layers. Empty layers are removed.",
          "minimum": 0,
          "maximum": 14
        }
      },
      "required": [
        "type",
        "id",
        "layer"
      ],
      "additionalProperties": false
    }
  },
  "limits": {
    "maxBytes": 262144,
    "maxElements": 100,
    "maxLayers": 15
  },
  "limitations": [
    "One saved existing page, same stable element IDs/types/source slot set. Add, duplicate or remove elements with apply_project_changes (element.add/duplicate/remove), then export the page again; pages and languages have their own tools.",
    "Only fields the export shows may be supplied, plus any field the element (or its title/subtitle) leaves unset, where the editor's default applies; maxFontSize on a locked text block needs fontSizeLock:false. Other omitted native-only/unsupported fields are preserved, not reset or flattened.",
    "apply_project_changes element.update changes one element with these same fields and rules: objects merge field by field, a colour or gradient, an array or any other value replaces.",
    "Fonts are names already on the page or from list_fonts (Google Fonts and the account's uploaded fonts); font URLs are never accepted.",
    "Solid RGBA is editable everywhere; page backgrounds, shape fill/stroke, image frame fill/border, SVG colour/stroke and text decoration also take two-colour gradients. Background images use background.set; inline gradients/highlights use text.set. Unsupported native settings remain preserved.",
    "Rich run count/order remains fixed. Translations, project globals, fallback source slots and all sibling pages are preserved.",
    "Validity does not guarantee visual readability or target-specific device assets. Render/inspect a preview and run existing export/upload validation."
  ],
  "commands": {
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "oneOf": [
      {
        "type": "object",
        "properties": {
          "op": {
            "type": "string",
            "const": "color.replace"
          },
          "from": {
            "type": "string",
            "pattern": "^#(?:[\\da-f]{3,4}|[\\da-f]{6}|[\\da-f]{8})$",
            "description": "Existing RGB hex colour from get_project_design, for example #663399."
          },
          "to": {
            "type": "string",
            "pattern": "^#(?:[\\da-f]{3,4}|[\\da-f]{6}|[\\da-f]{8})$",
            "description": "Replacement hex colour, for example an app colour from get_app. Any alpha suffix is ignored."
          }
        },
        "required": [
          "op",
          "from",
          "to"
        ],
        "additionalProperties": false,
        "description": "Replaces a colour across the project with the editor's Color replacer. Keeps each use's opacity and changes editable styles, including gradient stops and translated text, without changing image pixels."
      },
      {
        "type": "object",
        "properties": {
          "op": {
            "type": "string",
            "const": "element.add"
          },
          "screenshotId": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "text",
              "device",
              "image",
              "shape"
            ]
          },
          "elementId": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{8,128}$",
            "description": "Optional ID for the new element (8 to 128 letters, digits, - or _), so later operations in the same call can use it."
          },
          "referenceElementId": {
            "description": "An element on the page to place it by, as the editor's Add Element does: the new element takes its x, y and width.",
            "type": "string"
          },
          "addTo": {
            "default": "layer",
            "description": "layer: a new top layer, placed freely, at most 15 per page. above/below: in the reference element's existing stack, which saves new positions for the elements it pushes (warning ELEMENTS_PUSHED); moving the new element out later does not move them back.",
            "type": "string",
            "enum": [
              "layer",
              "above",
              "below"
            ]
          },
          "addSize": {
            "default": "push",
            "description": "push: the stack grows. squeeze: the stack keeps its height and its elements shrink to fit.",
            "type": "string",
            "enum": [
              "push",
              "squeeze"
            ]
          }
        },
        "required": [
          "op",
          "screenshotId",
          "type"
        ],
        "additionalProperties": false,
        "description": "Adds a text, device, image or shape element styled like the first element of its type in the project, as the editor does. It takes the reference element's x, y and width, and is 0.2 tall (a device 0.5). Then set its text, screenshots or image with the usual tools."
      },
      {
        "type": "object",
        "properties": {
          "op": {
            "type": "string",
            "const": "element.duplicate"
          },
          "elementId": {
            "type": "string"
          },
          "newElementId": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{8,128}$",
            "description": "Optional ID for the new element (8 to 128 letters, digits, - or _), so later operations in the same call can use it."
          }
        },
        "required": [
          "op",
          "elementId"
        ],
        "additionalProperties": false,
        "description": "Copies an element with its text, translations and images into a new layer above it, offset slightly, as the editor's Duplicate does."
      },
      {
        "type": "object",
        "properties": {
          "op": {
            "type": "string",
            "const": "element.remove"
          },
          "elementId": {
            "type": "string"
          }
        },
        "required": [
          "op",
          "elementId"
        ],
        "additionalProperties": false,
        "description": "Deletes an element; the rest of its stack closes up, as in the editor."
      },
      {
        "type": "object",
        "properties": {
          "op": {
            "type": "string",
            "const": "element.continue"
          },
          "elementId": {
            "type": "string"
          },
          "direction": {
            "type": "string",
            "enum": [
              "left",
              "right"
            ]
          },
          "newElementId": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{8,128}$",
            "description": "Optional ID for the new element (8 to 128 letters, digits, - or _), so later operations in the same call can use it."
          }
        },
        "required": [
          "op",
          "elementId",
          "direction"
        ],
        "additionalProperties": false,
        "description": "Continue on Screen: for an element that runs off the left or right edge of its page, places the matching copy on the neighbouring page so it carries across the set."
      },
      {
        "type": "object",
        "properties": {
          "op": {
            "type": "string",
            "const": "background.set"
          },
          "scope": {
            "type": "string",
            "enum": [
              "project",
              "page"
            ],
            "description": "project: the panoramic background that spans every page. page: one page's own background, drawn on top."
          },
          "screenshotId": {
            "description": "Required for scope page.",
            "type": "string"
          },
          "paint": {
            "description": "Background colour or gradient; accepts hex, rgb() and rgba() strings; null for none.",
            "anyOf": [
              {
                "anyOf": [
                  {
                    "type": "object",
                    "properties": {
                      "rgba": {
                        "minItems": 4,
                        "maxItems": 4,
                        "type": "array",
                        "items": {
                          "type": "number",
                          "minimum": 0,
                          "maximum": 255
                        },
                        "description": "[R,G,B,alpha]: numeric RGB integers 0..255; alpha 0..1."
                      }
                    },
                    "required": [
                      "rgba"
                    ],
                    "additionalProperties": false
                  },
                  {
                    "type": "object",
                    "properties": {
                      "gradient": {
                        "type": "object",
                        "properties": {
                          "style": {
                            "type": "string",
                            "enum": [
                              "linear",
                              "radial"
                            ]
                          },
                          "angle": {
                            "type": "number",
                            "minimum": -360,
                            "maximum": 360,
                            "description": "Linear: degrees. Radial: radius as a percentage (1..100)."
                          },
                          "from": {
                            "anyOf": [
                              {
                                "type": "object",
                                "properties": {
                                  "rgba": {
                                    "minItems": 4,
                                    "maxItems": 4,
                                    "type": "array",
                                    "items": {
                                      "type": "number",
                                      "minimum": 0,
                                      "maximum": 255
                                    },
                                    "description": "[R,G,B,alpha]: numeric RGB integers 0..255; alpha 0..1."
                                  }
                                },
                                "required": [
                                  "rgba"
                                ],
                                "additionalProperties": false
                              },
                              {
                                "type": "string",
                                "maxLength": 1000,
                                "description": "Hex (3/4/6/8 digits), rgb(), rgba() or transparent."
                              }
                            ]
                          },
                          "to": {
                            "anyOf": [
                              {
                                "type": "object",
                                "properties": {
                                  "rgba": {
                                    "minItems": 4,
                                    "maxItems": 4,
                                    "type": "array",
                                    "items": {
                                      "type": "number",
                                      "minimum": 0,
                                      "maximum": 255
                                    },
                                    "description": "[R,G,B,alpha]: numeric RGB integers 0..255; alpha 0..1."
                                  }
                                },
                                "required": [
                                  "rgba"
                                ],
                                "additionalProperties": false
                              },
                              {
                                "type": "string",
                                "maxLength": 1000,
                                "description": "Hex (3/4/6/8 digits), rgb(), rgba() or transparent."
                              }
                            ]
                          },
                          "stopFrom": {
                            "type": "number",
                            "minimum": 0,
                            "maximum": 1
                          },
                          "stopTo": {
                            "type": "number",
                            "minimum": 0,
                            "maximum": 1
                          }
                        },
                        "required": [
                          "style",
                          "angle",
                          "from",
                          "to",
                          "stopFrom",
                          "stopTo"
                        ],
                        "additionalProperties": false
                      }
                    },
                    "required": [
                      "gradient"
                    ],
                    "additionalProperties": false
                  },
                  {
                    "type": "string",
                    "maxLength": 1000,
                    "description": "Hex, rgb(), rgba(), transparent or a saved native gradient."
                  }
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "image": {
            "description": "One image shared by all output sizes and languages, scaled to cover the background. Setting or removing it clears any old variants.",
            "type": "object",
            "properties": {
              "assetId": {
                "description": "An uploaded asset or a list_library_images ID; null removes the background image. Omit to adjust the existing image.",
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 1000
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "position": {
                "type": "string",
                "enum": [
                  "topMiddle",
                  "topLeft",
                  "topRight",
                  "middle",
                  "middleLeft",
                  "middleRight",
                  "bottomMiddle",
                  "bottomLeft",
                  "bottomRight"
                ]
              },
              "rotation": {
                "anyOf": [
                  {
                    "type": "number",
                    "const": 0
                  },
                  {
                    "type": "number",
                    "const": 90
                  },
                  {
                    "type": "number",
                    "const": 180
                  },
                  {
                    "type": "number",
                    "const": 270
                  }
                ]
              }
            },
            "additionalProperties": false
          },
          "pattern": {
            "description": "A tiled motif over the background; null removes it. Colours accept hex, rgb() and rgba() strings.",
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "style": {
                    "type": "string",
                    "enum": [
                      "dots",
                      "grid",
                      "diagonalLines",
                      "crosshatch",
                      "diamonds",
                      "waves"
                    ]
                  },
                  "color": {
                    "anyOf": [
                      {
                        "type": "object",
                        "properties": {
                          "rgba": {
                            "minItems": 4,
                            "maxItems": 4,
                            "type": "array",
                            "items": {
                              "type": "number",
                              "minimum": 0,
                              "maximum": 255
                            },
                            "description": "[R,G,B,alpha]: numeric RGB integers 0..255; alpha 0..1."
                          }
                        },
                        "required": [
                          "rgba"
                        ],
                        "additionalProperties": false
                      },
                      {
                        "type": "string",
                        "maxLength": 1000,
                        "description": "Hex (3/4/6/8 digits), rgb(), rgba() or transparent."
                      }
                    ]
                  },
                  "opacity": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 100
                  },
                  "size": {
                    "type": "number",
                    "minimum": 10,
                    "maximum": 1000
                  },
                  "spacing": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 300
                  },
                  "rotation": {
                    "type": "number",
                    "minimum": -359,
                    "maximum": 359
                  }
                },
                "additionalProperties": false
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "op",
          "scope"
        ],
        "additionalProperties": false,
        "description": "Sets the panoramic project background or a page background: colour or gradient, image and pattern, as the background controls do. Leave a part out to keep it."
      },
      {
        "type": "object",
        "properties": {
          "op": {
            "type": "string",
            "const": "element.update"
          },
          "elementId": {
            "type": "string"
          },
          "changes": {
            "type": "object",
            "propertyNames": {
              "type": "string"
            },
            "additionalProperties": {},
            "description": "Fields of this element as export_project_design_document shows them (location, rotation, opacity, shadow, frame, appearance, fit, fill, title {font, align, color, ...} and so on), or one it leaves at the editor's default. Objects merge field by field; a colour or gradient, an array or any other value replaces."
          }
        },
        "required": [
          "op",
          "elementId",
          "changes"
        ],
        "additionalProperties": false,
        "description": "Changes one element's design, with the same fields, checks and stacking rules as the design document."
      },
      {
        "type": "object",
        "properties": {
          "op": {
            "type": "string",
            "const": "element.transform"
          },
          "elementId": {
            "type": "string"
          },
          "transform": {
            "type": "object",
            "properties": {
              "units": {
                "default": "%",
                "description": "The element's own units from get_project_element: % fractions (0.5 is half the canvas) or px. Values are not converted.",
                "type": "string",
                "enum": [
                  "%",
                  "px"
                ]
              },
              "x": {
                "type": "number",
                "minimum": -100000,
                "maximum": 100000
              },
              "y": {
                "description": "Only the top element of a layer's stack can move vertically; the rest follow the element above, as in the editor.",
                "type": "number",
                "minimum": -100000,
                "maximum": 100000
              },
              "width": {
                "type": "number",
                "minimum": 0,
                "maximum": 100000
              },
              "height": {
                "description": "Changing a stacked element's height moves the elements below it.",
                "type": "number",
                "minimum": 0,
                "maximum": 100000
              },
              "rotation": {
                "type": "number",
                "minimum": -359,
                "maximum": 359
              }
            },
            "additionalProperties": false
          }
        },
        "required": [
          "op",
          "elementId",
          "transform"
        ],
        "additionalProperties": false,
        "description": "Shortcut for element.update location and rotation."
      },
      {
        "type": "object",
        "properties": {
          "op": {
            "type": "string",
            "const": "element.set_opacity"
          },
          "elementId": {
            "type": "string"
          },
          "opacity": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100,
            "description": "Element opacity percentage. 0 is transparent and 100 is fully opaque."
          }
        },
        "required": [
          "op",
          "elementId",
          "opacity"
        ],
        "additionalProperties": false,
        "description": "Shortcut for element.update opacity."
      },
      {
        "type": "object",
        "properties": {
          "op": {
            "type": "string",
            "const": "text.set"
          },
          "elementId": {
            "type": "string"
          },
          "slot": {
            "type": "string",
            "enum": [
              "title",
              "subtitle"
            ]
          },
          "language": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "maxLength": 32
              },
              {
                "type": "null"
              }
            ]
          },
          "value": {
            "type": "object",
            "properties": {
              "ops": {
                "minItems": 1,
                "maxItems": 500,
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "insert": {
                      "type": "string",
                      "maxLength": 20000
                    },
                    "attributes": {
                      "description": "Inline formatting: bold, italic, underline, color, gradient, background.",
                      "type": "object",
                      "propertyNames": {
                        "type": "string"
                      },
                      "additionalProperties": {}
                    }
                  },
                  "required": [
                    "insert"
                  ],
                  "additionalProperties": false
                }
              }
            },
            "required": [
              "ops"
            ],
            "additionalProperties": false,
            "description": "Formatted text, e.g. {ops:[{insert:\"Reach anyone\\n\"}]}, not a plain string. A title or subtitle has at most 250 characters across its runs, excluding its final newline. Unchanged legacy text can retain formatting edits."
          },
          "clearFormatting": {
            "default": false,
            "description": "Plain text keeps a block's single style. For text with mixed formatting, send formatted runs, or true to replace it with plain text.",
            "type": "boolean"
          }
        },
        "required": [
          "op",
          "elementId",
          "slot",
          "value"
        ],
        "additionalProperties": false
      },
      {
        "type": "object",
        "properties": {
          "op": {
            "type": "string",
            "const": "text.set_style"
          },
          "elementId": {
            "type": "string"
          },
          "slot": {
            "type": "string",
            "enum": [
              "title",
              "subtitle"
            ]
          },
          "language": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "maxLength": 32
              },
              {
                "type": "null"
              }
            ]
          },
          "settings": {
            "type": "object",
            "properties": {
              "fontAlign": {
                "type": "string",
                "enum": [
                  "left",
                  "center",
                  "right"
                ]
              },
              "fontFamily": {
                "anyOf": [
                  {
                    "type": "object",
                    "properties": {
                      "name": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 120
                      },
                      "source": {
                        "anyOf": [
                          {
                            "type": "string",
                            "maxLength": 500
                          },
                          {
                            "type": "null"
                          }
                        ]
                      }
                    },
                    "required": [
                      "name"
                    ],
                    "additionalProperties": false
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "global": {
                "type": "boolean"
              },
              "charSpacing": {
                "description": "Fraction of font size. Base-language text is limited to 0.25; translated overrides may use up to 9.99.",
                "type": "number",
                "minimum": 0,
                "maximum": 9.99
              },
              "lineHeight": {
                "type": "number",
                "minimum": 0.01,
                "maximum": 3
              },
              "maxFontSize": {
                "description": "Base-language text only. Normalized canvas units, not pixels: 0.1 is displayed as 10 in the UI. Needs fontSizeLock:false, which takes this block out of the matched set size; prefer shorter copy or a larger text box.",
                "type": "number",
                "minimum": 0.005,
                "maximum": 1
              },
              "fontSizeLock": {
                "description": "Base-language text only. True (Match text size, recommended) gives every matched caption the size of the smallest one that fits, per language and output size, so the set stays consistent; false enables manual maxFontSize for this block only.",
                "type": "boolean"
              }
            },
            "additionalProperties": false
          }
        },
        "required": [
          "op",
          "elementId",
          "slot",
          "settings"
        ],
        "additionalProperties": false,
        "description": "Sets the text style in the default language (null), which every language follows, or one language's own style, as the translation panel does: a value equal to what the language inherits clears its override, and an automatic translation stays automatic."
      },
      {
        "type": "object",
        "properties": {
          "op": {
            "type": "string",
            "const": "screenshot.remove"
          },
          "screenshotId": {
            "type": "string"
          }
        },
        "required": [
          "op",
          "screenshotId"
        ],
        "additionalProperties": false
      },
      {
        "type": "object",
        "properties": {
          "op": {
            "type": "string",
            "const": "screenshot.reorder"
          },
          "screenshotIds": {
            "minItems": 1,
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "op",
          "screenshotIds"
        ],
        "additionalProperties": false
      },
      {
        "type": "object",
        "properties": {
          "op": {
            "type": "string",
            "const": "device.set_frame"
          },
          "elementId": {
            "type": "string"
          },
          "settings": {
            "type": "object",
            "properties": {
              "device": {
                "description": "Native frame variant. Perspective variants are registered frame assets, not arbitrary 3D rotation.",
                "type": "string",
                "enum": [
                  "full",
                  "dynamic",
                  "none",
                  "cover",
                  "warpleft",
                  "warpright",
                  "nonewarpleft",
                  "nonewarpright"
                ]
              },
              "deviceType": {
                "description": "Native appearance. Availability varies by output target; inspect a rendered preview.",
                "type": "string",
                "enum": [
                  "black",
                  "reallight",
                  "realgold",
                  "light",
                  "dark",
                  "granite",
                  "silver",
                  "mint",
                  "apple",
                  "earth",
                  "green",
                  "rose",
                  "strawberry",
                  "bluelagoon",
                  "space",
                  "berry",
                  "lemon",
                  "gold",
                  "coral"
                ]
              },
              "orientation": {
                "type": "string",
                "enum": [
                  "portrait",
                  "landscapeleft",
                  "landscaperight"
                ]
              },
              "blankWhenEmpty": {
                "description": "Show a plain dark screen when no capture is available. Assigned captures still render.",
                "type": "boolean"
              },
              "imageSize": {
                "description": "Native contain/covertop/coverbottom/covercenter. cover and fill are not supported image modes.",
                "type": "string",
                "enum": [
                  "contain",
                  "covertop",
                  "coverbottom",
                  "covercenter"
                ]
              },
              "rotation": {
                "type": "number",
                "minimum": -359,
                "maximum": 359
              }
            },
            "additionalProperties": false
          }
        },
        "required": [
          "op",
          "elementId",
          "settings"
        ],
        "additionalProperties": false,
        "description": "Shortcut for element.update frame, appearance, orientation, empty screen, fit and rotation."
      }
    ]
  }
}
