{
  "$id": "https://quailpages.com/schema/qp.schema.json",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$ref": "#/definitions/QuailPagesAuthoredDocument",
  "definitions": {
    "QuailPagesAuthoredDocument": {
      "anyOf": [
        {
          "$ref": "#/definitions/SiteDocument"
        },
        {
          "$ref": "#/definitions/PageDocument"
        },
        {
          "$ref": "#/definitions/Component"
        }
      ],
      "description": "Any top-level persisted JSON document recognized by Quail Pages.\n\nQuail Pages defines three core document types:\n\n- `SiteDocument` — saved as `site.config.json` at the site root.\n- `PageDocument` — stored beneath `pages/` and mapped to a public URL by   the site manifest independently of its source location.\n- `Component` — conventionally stored beneath `components/`.\n\nA complete site source may also contain:\n\n- `assets/` — static files such as favicons, manifests, PDFs, and other   public resources. Asset contents are copied into the generated site's   public root, so `assets/favicon.svg` is published as `/favicon.svg`.   Assets are commonly referenced by `site.config.json`, pages, and   components, but are not authored JSON document types.\n- `plugins/` — optional plugin-owned resources and data. Plugin-owned data   files are not additional core Quail Pages document roots.\n\nTogether, the authored documents, static assets, and optional plugin resources form the source of a complete Quail Pages website."
    },
    "SiteDocument": {
      "type": "object",
      "properties": {
        "title": {
          "type": "string",
          "description": "Visible heading or display name."
        },
        "description": {
          "type": "string",
          "description": "Summary used by content or metadata."
        },
        "url": {
          "type": "string",
          "description": "Canonical public base URL."
        },
        "imageBaseUrl": {
          "type": "string",
          "description": "Optional image-service base URL used to expand site-relative images."
        },
        "imageDefaults": {
          "$ref": "#/definitions/SiteImageDefaults",
          "description": "Site-wide defaults for authored images."
        },
        "theme": {
          "type": "string",
          "description": "Registered theme identifier."
        },
        "plugins": {
          "$ref": "#/definitions/SitePlugins",
          "description": "Site-wide plugin configuration keyed by registered plugin ID."
        },
        "variables": {
          "$ref": "#/definitions/SiteVariables",
          "description": "Values available to inline interpolation."
        },
        "pages": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/PageRoute"
          },
          "description": "Page sources beneath `pages/` and their independent public paths."
        },
        "generatedPages": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/PageRoute"
          },
          "description": "Machine-generated page sources beneath `pages/` and their independent public paths.\n\nUses the same manifest contract as `pages`; the distinction is ownership, not routing or rendering behavior. Generators may replace this collection. Sources remain relative to the site's `pages/` directory.",
          "qpUseWhen": "A generator owns reusable or reference pages that coexist with authored pages."
        },
        "branding": {
          "$ref": "#/definitions/SiteBranding",
          "description": "Browser, installed-app, and publisher-logo presentation."
        },
        "identity": {
          "$ref": "#/definitions/SiteIdentity",
          "description": "Structured organization and brand identity used by discovery metadata."
        },
        "header": {
          "$ref": "#/definitions/SiteHeader",
          "description": "Site header content."
        },
        "footer": {
          "$ref": "#/definitions/SiteFooter",
          "description": "Site footer content."
        },
        "socials": {
          "$ref": "#/definitions/SiteSocials",
          "description": "References site social definitions."
        },
        "authors": {
          "$ref": "#/definitions/SiteAuthors",
          "description": "Author profiles keyed by the page-authored display name."
        }
      },
      "required": [
        "title",
        "url",
        "theme",
        "pages"
      ],
      "additionalProperties": false,
      "description": "The persisted root configuration for a Quail Pages site.\n\nThis document is saved as `site.config.json` at the root of a complete Quail Pages site source.\n\nA complete site source is organized around `site.config.json` with supporting authored content in sibling directories:\n\n- `pages/` contains authored PageDocument JSON files.\n- `components/` contains reusable Component JSON files.\n- `assets/` contains static files copied into the generated site's public root.\n- `plugins/` contains site plugin resources and configuration owned by plugins.\n\nSource directory names are not necessarily part of their public paths. For example, `assets/favicon.svg` is published as `/favicon.svg`. Every page manifest `source` is relative to `pages/`; its independent `path` explicitly maps that PageDocument to a public URL.",
      "qpUseWhen": "Authoring `site.config.json` or packaging a complete Quail Pages\nsite source.",
      "qpAvoidWhen": "Authoring an individual page or reusable component; use a\nPageDocument or Component instead."
    },
    "SiteImageDefaults": {
      "type": "object",
      "properties": {
        "lightbox": {
          "type": "boolean",
          "description": "Enables lightbox behavior when an image does not override it.",
          "examples": [
            true
          ]
        }
      },
      "required": [
        "lightbox"
      ],
      "additionalProperties": false,
      "description": "Site-wide defaults for image interaction."
    },
    "SitePlugins": {
      "type": "object",
      "additionalProperties": {
        "$ref": "#/definitions/PluginConfig"
      },
      "description": "Registered site plugins keyed by plugin ID.\n\nEach property enables that plugin for the site. Its value contains the plugin-owned site configuration and may be empty when no options are required.",
      "examples": [
        {
          "events": {},
          "google-analytics": {},
          "featherquest/newsletter": {}
        }
      ],
      "qpUseWhen": "Enable and optionally configure plugins for the site."
    },
    "PluginConfig": {
      "type": "object",
      "additionalProperties": {},
      "description": "Site configuration owned by a registered plugin.\n\nAn empty object enables a plugin that requires no site-level options. Additional properties are defined and interpreted by the plugin rather than Quail Pages core.",
      "examples": [
        {
          "option": "value"
        }
      ],
      "qpUseWhen": "A registered plugin needs site-level configuration, or no\nadditional configuration beyond being enabled for the site.",
      "qpAvoidWhen": "Data belongs to one specific PluginRef invocation rather\nthan the plugin's site-wide configuration."
    },
    "SiteVariables": {
      "type": "object",
      "additionalProperties": {},
      "description": "Named values available to inline interpolation.",
      "examples": [
        {
          "contactEmail": "hello@example.com",
          "monthlyPrice": "$29",
          "annualPrice": "$290"
        }
      ],
      "qpUseWhen": "Use for reusable site-wide values that authored content references through interpolation.",
      "qpAvoidWhen": "The value represents structured page content, plugin configuration, or a reusable content block; use the appropriate page, plugin, or component contract instead."
    },
    "PageRoute": {
      "type": "object",
      "properties": {
        "source": {
          "type": "string",
          "description": "Path to the authored PageDocument, relative to the site's `pages/` directory."
        },
        "path": {
          "type": "string",
          "description": "Public page path, independent of the PageDocument's source location."
        }
      },
      "required": [
        "source",
        "path"
      ],
      "additionalProperties": false,
      "description": "Maps a page source to its public path.",
      "examples": [
        {
          "source": "root/index.json",
          "path": "/"
        }
      ]
    },
    "SiteBranding": {
      "type": "object",
      "properties": {
        "publisherLogo": {
          "type": "string",
          "description": "Publisher image included in Organization and legacy Article JSON-LD.",
          "qpRecommend": "Supply a publisher logo for complete article structured data."
        },
        "faviconIco": {
          "type": "string",
          "description": "ICO favicon path.",
          "qpRecommend": "Supply an ICO favicon for broad browser compatibility."
        },
        "faviconSvg": {
          "type": "string",
          "description": "SVG favicon path.",
          "qpRecommend": "Supply an SVG favicon for modern browsers and high-resolution displays."
        },
        "appleTouchIcon": {
          "type": "string",
          "description": "Apple touch-icon path.",
          "qpRecommend": "Supply an Apple touch icon for saved sites on Apple devices."
        },
        "manifest": {
          "type": "string",
          "description": "Web app manifest path.",
          "examples": [
            "/site.webmanifest"
          ],
          "qpRecommend": "Supply a web app manifest for complete browser and installed-app metadata."
        },
        "appTitle": {
          "type": "string",
          "description": "Installed-app title.",
          "qpRecommend": "Supply an app title for installed and saved site experiences."
        },
        "themeColor": {
          "type": "string",
          "description": "Browser and app theme color.",
          "examples": [
            "#0f172a"
          ],
          "qpRecommend": "Supply a theme color consistent with the site's visual identity."
        }
      },
      "additionalProperties": false,
      "description": "Site browser/install presentation and publisher logo assets.\n\nBranding files are authored as site assets and referenced here by their public paths. Best practice is to place root-level browser assets such as favicons, touch icons, and the web app manifest in the site's assets directory. Quail Pages copies site assets into the generated site while preserving their public paths, allowing files intended for the web root to be referenced from paths such as `/favicon.svg` or `/site.webmanifest`.",
      "qpUseWhen": "Use for site-wide logo assets, favicons, installed-app metadata,\nand browser presentation."
    },
    "SiteIdentity": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string",
          "description": "Public organization name."
        },
        "legalName": {
          "type": "string",
          "description": "Registered or other formal organization name, when different."
        },
        "organizationId": {
          "type": "string",
          "description": "Absolute or site-relative JSON-LD identifier. Defaults to `#organization`."
        },
        "brand": {
          "$ref": "#/definitions/SiteBrandIdentity",
          "description": "Optional public brand owned by the organization."
        }
      },
      "required": [
        "name"
      ],
      "additionalProperties": false,
      "description": "Structured identity for the organization responsible for a site and its optional public brand.",
      "qpUseWhen": "The site should publish a reusable Organization identity in\nstructured discovery metadata.",
      "qpAvoidWhen": "Configuring logos, favicons, installed-app metadata, or browser\npresentation; use SiteBranding for those presentation concerns."
    },
    "SiteBrandIdentity": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string",
          "description": "Public brand name."
        },
        "id": {
          "type": "string",
          "description": "Absolute or site-relative JSON-LD identifier. Defaults to `#brand`."
        },
        "identifiers": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/SiteIdentityIdentifier"
          },
          "description": "Generic identifiers associated with this brand."
        }
      },
      "required": [
        "name"
      ],
      "additionalProperties": false,
      "description": "A named public brand associated with the site organization."
    },
    "SiteIdentityIdentifier": {
      "type": "object",
      "properties": {
        "propertyID": {
          "type": "string",
          "description": "Namespace or registry describing the identifier."
        },
        "value": {
          "type": "string",
          "description": "Identifier value in the named namespace or registry."
        }
      },
      "required": [
        "propertyID",
        "value"
      ],
      "additionalProperties": false,
      "description": "A generic external or internal identifier for a site identity."
    },
    "SiteHeader": {
      "type": "object",
      "properties": {
        "sections": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/PageSection"
          },
          "description": "Sections rendered in authored order within the site header."
        }
      },
      "required": [
        "sections"
      ],
      "additionalProperties": false,
      "description": "Site-wide header content organized into authored sections.",
      "examples": [
        {
          "sections": [
            {
              "id": "site-header",
              "title": "Site header",
              "titleSrOnly": true,
              "elements": [
                {
                  "type": "image",
                  "src": "/branding/logo.svg",
                  "alt": "Acme Home",
                  "loading": "eager",
                  "fetchPriority": "high",
                  "link": {
                    "href": "/"
                  },
                  "class": "site-logo"
                },
                {
                  "type": "menu",
                  "navId": "qp-primary-nav",
                  "mobileCollapse": true,
                  "ariaLabel": "Primary navigation",
                  "items": [
                    {
                      "label": "Home",
                      "link": {
                        "href": "/"
                      }
                    },
                    {
                      "label": "Pricing",
                      "link": {
                        "href": "/pricing/"
                      }
                    }
                  ]
                }
              ]
            }
          ]
        }
      ],
      "qpUseWhen": "Use for navigation and identity content that should appear in the site's header across pages.",
      "qpAvoidWhen": "The content applies only to one page or a subset of pages; keep it in the page or use a reusable component."
    },
    "PageSection": {
      "anyOf": [
        {
          "$ref": "#/definitions/StandardSection"
        },
        {
          "$ref": "#/definitions/RegionSection"
        },
        {
          "$ref": "#/definitions/Divider"
        },
        {
          "$ref": "#/definitions/Modal"
        },
        {
          "$ref": "#/definitions/StickyTray"
        },
        {
          "$ref": "#/definitions/Toc"
        },
        {
          "$ref": "#/definitions/PluginRef"
        },
        {
          "$ref": "#/definitions/ComponentRef"
        }
      ],
      "description": "Any authored item allowed directly in a page's `sections` array. Modal may be placed here or inside a normal Section because its authored position does not affect its runtime presentation."
    },
    "StandardSection": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "elements": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/Element"
          },
          "description": "Elements rendered in authored order."
        },
        "type": {
          "type": "string",
          "const": "section",
          "description": "Identifies this as a standard content section."
        },
        "id": {
          "type": "string",
          "description": "Stable document, section, or region identifier."
        },
        "title": {
          "type": "string",
          "description": "Semantic section heading."
        },
        "titleSrOnly": {
          "type": "boolean",
          "description": "Renders the section heading visually hidden but available to screen readers."
        },
        "subtitle": {
          "type": "string",
          "description": "Supporting text associated with the heading."
        },
        "width": {
          "type": "string",
          "enum": [
            "default",
            "wide",
            "full",
            "theme"
          ],
          "description": "Standard section width treatment. Defaults to `default` when omitted. `default` uses the standard constrained content width with normal outer breathing room. `wide` uses a wider constrained content width while retaining normal outer breathing room. `full` is a full-bleed treatment whose section surface extends edge-to-edge without an outer inline gutter or corner treatment by default; use it for backgrounds, imagery, media, and other continuous surfaces. Child content may remain independently constrained. `theme` applies no standard width treatment; the authored `class` and active theme own the width behavior.",
          "default": "default"
        },
        "appearance": {
          "type": "string",
          "enum": [
            "default",
            "alternate",
            "transparent",
            "theme"
          ],
          "description": "Standard section surface treatment. Defaults to `default` when omitted. `default` uses the standard Base/theme section surface. `alternate` uses the standard visually distinct alternate surface while retaining normal section structure. `transparent` removes the standard section surface so the surrounding page or background shows through while retaining normal section structure. `theme` emits no standard appearance class and opts out of the complete standard Section surface recipe. The authored `class` and active theme own its background, foreground, internal padding, border, radius, shadow, and other surface behavior. Use it to replace the standard composition rather than merely recolor it. When the custom appearance creates a visible surface boundary, the theme must provide an appropriate internal inset; it may explicitly reuse the standard Section surface padding variables.",
          "default": "default"
        },
        "class": {
          "type": "string",
          "description": "Optional styling hook."
        }
      },
      "required": [
        "elements",
        "id",
        "title"
      ],
      "description": "A section with one normal element flow."
    },
    "Element": {
      "anyOf": [
        {
          "$ref": "#/definitions/CardList"
        },
        {
          "$ref": "#/definitions/ComponentRef"
        },
        {
          "$ref": "#/definitions/Cta"
        },
        {
          "$ref": "#/definitions/Divider"
        },
        {
          "$ref": "#/definitions/Gallery"
        },
        {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "type": {
              "type": "string",
              "const": "image"
            },
            "src": {
              "type": "string",
              "description": "Image URL or site-relative path."
            },
            "alt": {
              "type": "string",
              "description": "Accessible text alternative."
            },
            "link": {
              "$ref": "#/definitions/Link",
              "description": "Optional ordinary navigation link; overrides lightbox behavior."
            },
            "lightbox": {
              "type": "boolean",
              "description": "Overrides the site-wide image lightbox default."
            },
            "badge": {
              "type": "string",
              "description": "Short label displayed over the image."
            },
            "class": {
              "type": "string",
              "description": "Optional styling hook."
            },
            "width": {
              "type": "number",
              "description": "Maximum responsive source width.",
              "minimum": 1
            },
            "loading": {
              "type": "string",
              "enum": [
                "lazy",
                "eager"
              ],
              "description": "Browser loading strategy."
            },
            "fetchPriority": {
              "type": "string",
              "enum": [
                "high",
                "low",
                "auto"
              ],
              "description": "Browser fetch-priority hint."
            },
            "maxWidth": {
              "type": "number",
              "description": "Maximum rendered width in CSS pixels."
            },
            "aspectRatio": {
              "type": "string",
              "description": "Preferred rendered aspect ratio, expressed as a ratio such as `5:7` or `16:9`."
            },
            "centerOffset": {
              "type": "object",
              "properties": {
                "x": {
                  "type": "number",
                  "description": "Horizontal focal position."
                },
                "y": {
                  "type": "number",
                  "description": "Vertical focal position."
                }
              },
              "additionalProperties": false,
              "description": "Percentage focal position; missing axes default to 50."
            },
            "caption": {
              "type": "object",
              "properties": {
                "title": {
                  "type": "string",
                  "description": "Visible heading or display name."
                },
                "subtitle": {
                  "type": "string",
                  "description": "Supporting text associated with the heading."
                },
                "credit": {
                  "type": "string",
                  "description": "Image credit text."
                }
              },
              "additionalProperties": false,
              "description": "Structured media caption."
            }
          },
          "required": [
            "alt",
            "src",
            "type"
          ]
        },
        {
          "$ref": "#/definitions/List"
        },
        {
          "$ref": "#/definitions/Menu"
        },
        {
          "$ref": "#/definitions/Modal"
        },
        {
          "$ref": "#/definitions/PageList"
        },
        {
          "$ref": "#/definitions/Paragraph"
        },
        {
          "$ref": "#/definitions/PluginRef"
        },
        {
          "$ref": "#/definitions/ProductList"
        },
        {
          "$ref": "#/definitions/Socials"
        },
        {
          "$ref": "#/definitions/StickyTray"
        },
        {
          "$ref": "#/definitions/Toc"
        },
        {
          "$ref": "#/definitions/Video"
        }
      ],
      "description": "Reusable authored content elements supported in sections and nested content structures."
    },
    "CardList": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "const": "card-list",
          "description": "Identifies the Element type represented by this object."
        },
        "class": {
          "type": "string",
          "description": "Optional styling hook."
        },
        "cardClass": {
          "type": "string",
          "description": "Optional theme styling hook of the individual children cards."
        },
        "columns": {
          "type": "number",
          "description": "Controls the preferred number of cards per row; the grid may use fewer columns when space is limited.",
          "minimum": 1,
          "maximum": 4,
          "multipleOf": 1
        },
        "cards": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/Card"
          },
          "description": "A list of cards rendered in their display order.",
          "minItems": 1
        }
      },
      "required": [
        "type",
        "cards"
      ],
      "additionalProperties": false,
      "description": "A responsive grid of authored cards.",
      "examples": [
        {
          "type": "card-list",
          "columns": 2,
          "cards": [
            {
              "title": "Getting Started",
              "elements": [
                {
                  "type": "paragraph",
                  "text": "Learn the basics of birding."
                }
              ]
            },
            {
              "title": "Field Skills",
              "elements": [
                {
                  "type": "paragraph",
                  "text": "Practice identifying birds outdoors."
                }
              ]
            }
          ]
        }
      ],
      "qpUseWhen": "Use for peer items sharing a card presentation."
    },
    "Card": {
      "type": "object",
      "properties": {
        "title": {
          "type": "string",
          "description": "Visible heading or display name; required when the card links to a destination."
        },
        "icon": {
          "anyOf": [
            {
              "$ref": "#/definitions/Icon"
            },
            {
              "$ref": "#/definitions/Image"
            }
          ],
          "description": "Supporting icon or image."
        },
        "subtitle": {
          "type": "string",
          "description": "Supporting text associated with the heading."
        },
        "link": {
          "$ref": "#/definitions/Link",
          "description": "Optional navigation behavior."
        },
        "class": {
          "type": "string",
          "description": "Optional styling hook."
        },
        "elements": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/Element"
          },
          "description": "Elements rendered in authored order."
        }
      },
      "additionalProperties": false,
      "description": "Authored content for a card.\n*",
      "examples": [
        {
          "title": "Getting Started",
          "elements": [
            {
              "type": "paragraph",
              "text": "Learn the basics of birding."
            }
          ]
        }
      ]
    },
    "Icon": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string",
          "description": "Registered canonical QP icon name, or exactly one user-perceived Unicode grapheme rendered as an escaped symbol/emoji fallback. Values are strict and are not trimmed or normalized.",
          "format": "qp-icon-name"
        },
        "ariaLabel": {
          "type": "string",
          "description": "Optional accessible label; omit for a decorative icon."
        },
        "class": {
          "type": "string",
          "description": "Optional styling hook."
        }
      },
      "required": [
        "name"
      ],
      "additionalProperties": false,
      "description": "A supporting icon value rendered from the canonical QP icon registry or as an escaped single-grapheme symbol/emoji fallback. Unknown words and multi-grapheme strings are invalid.",
      "examples": [
        {
          "name": "search",
          "ariaLabel": "Search"
        }
      ],
      "qpRecommend": "Omit ariaLabel when the containing semantic object owns the\naccessible meaning. Add it only when the icon itself needs contextual\nscreen-reader text; registry descriptions are never automatic labels."
    },
    "Image": {
      "type": "object",
      "properties": {
        "src": {
          "type": "string",
          "description": "Image URL or site-relative path."
        },
        "alt": {
          "type": "string",
          "description": "Accessible text alternative."
        },
        "link": {
          "$ref": "#/definitions/Link",
          "description": "Optional ordinary navigation link; overrides lightbox behavior."
        },
        "lightbox": {
          "type": "boolean",
          "description": "Overrides the site-wide image lightbox default."
        },
        "badge": {
          "type": "string",
          "description": "Short label displayed over the image."
        },
        "class": {
          "type": "string",
          "description": "Optional styling hook."
        },
        "width": {
          "type": "number",
          "description": "Maximum responsive source width.",
          "minimum": 1
        },
        "loading": {
          "type": "string",
          "enum": [
            "lazy",
            "eager"
          ],
          "description": "Browser loading strategy."
        },
        "fetchPriority": {
          "type": "string",
          "enum": [
            "high",
            "low",
            "auto"
          ],
          "description": "Browser fetch-priority hint."
        },
        "maxWidth": {
          "type": "number",
          "description": "Maximum rendered width in CSS pixels."
        },
        "aspectRatio": {
          "type": "string",
          "description": "Preferred rendered aspect ratio, expressed as a ratio such as `5:7` or `16:9`."
        },
        "centerOffset": {
          "type": "object",
          "properties": {
            "x": {
              "type": "number",
              "description": "Horizontal focal position."
            },
            "y": {
              "type": "number",
              "description": "Vertical focal position."
            }
          },
          "additionalProperties": false,
          "description": "Percentage focal position; missing axes default to 50."
        },
        "caption": {
          "type": "object",
          "properties": {
            "title": {
              "type": "string",
              "description": "Visible heading or display name."
            },
            "subtitle": {
              "type": "string",
              "description": "Supporting text associated with the heading."
            },
            "credit": {
              "type": "string",
              "description": "Image credit text."
            }
          },
          "additionalProperties": false,
          "description": "Structured media caption."
        }
      },
      "required": [
        "src",
        "alt"
      ],
      "additionalProperties": false,
      "description": "Shared authored image data.",
      "examples": [
        {
          "src": "/images/team.jpg",
          "alt": "The Acme team working together",
          "aspectRatio": "16:9",
          "centerOffset": {
            "x": 50,
            "y": 40
          }
        }
      ],
      "qpUseWhen": "Use wherever Quail Pages expects image data. Add `type: \"image\"`\nwhen the image is a standalone Element; omit it when the image is nested\ninside another authored object."
    },
    "Link": {
      "type": "object",
      "properties": {
        "href": {
          "type": "string",
          "description": "Link destination."
        },
        "newTab": {
          "type": "boolean",
          "description": "Opens the destination in a new tab.",
          "default": false
        },
        "nofollow": {
          "type": "boolean",
          "description": "Adds `nofollow` to the anchor relationship.",
          "default": false
        },
        "sponsored": {
          "type": "boolean",
          "description": "Adds `sponsored` to the anchor relationship.",
          "default": false
        }
      },
      "required": [
        "href"
      ],
      "additionalProperties": false,
      "description": "Universal authored anchor behavior for structured content."
    },
    "ComponentRef": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "const": "component",
          "description": "Identifies the Element type represented by this object."
        },
        "component": {
          "type": "string",
          "description": "Key or source path of a non-nested persisted Component."
        }
      },
      "required": [
        "type",
        "component"
      ],
      "additionalProperties": false,
      "description": "A reference that includes persisted reusable component content.\n\nA ComponentRef may be authored wherever its containing contract permits a component reference. The referenced component is expanded once: persisted components may not contain another ComponentRef, including direct or indirect self-references.",
      "qpUseWhen": "Use when the same section or element group should appear\nin multiple places, such as shared endcaps, disclosures, navigation\nblocks, or calls to action.",
      "qpAvoidWhen": "The content is unique to one page or belongs globally in the site header/footer."
    },
    "Cta": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "const": "cta",
          "description": "Identifies the Element type represented by this object."
        },
        "class": {
          "type": "string",
          "description": "Optional styling hook."
        },
        "link": {
          "$ref": "#/definitions/Link",
          "description": "Navigation behavior."
        },
        "text": {
          "type": "string",
          "description": "Visible action text label."
        },
        "ariaLabel": {
          "type": "string",
          "description": "Accessible label that gives the action enough context to be understood independently of surrounding content."
        },
        "icon": {
          "$ref": "#/definitions/Icon",
          "description": "Optional supporting icon rendered before the action text."
        }
      },
      "required": [
        "type",
        "link",
        "text",
        "ariaLabel"
      ],
      "additionalProperties": false,
      "description": "A labeled link presented as an action.",
      "examples": [
        {
          "type": "cta",
          "link": {
            "href": "#example"
          },
          "text": "Explore Guides",
          "ariaLabel": "Explore birding guides"
        }
      ],
      "qpUseWhen": "Use when a link should be emphasized as an action."
    },
    "Divider": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "const": "divider",
          "description": "Identifies the Element type represented by this object."
        },
        "class": {
          "type": "string",
          "description": "Optional styling hook."
        }
      },
      "required": [
        "type"
      ],
      "additionalProperties": false,
      "description": "A thematic divider between elements.",
      "examples": [
        {
          "type": "divider"
        }
      ]
    },
    "Gallery": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "const": "gallery",
          "description": "Identifies the Element type represented by this object."
        },
        "class": {
          "type": "string",
          "description": "Optional styling hook."
        },
        "images": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/Image"
          },
          "description": "Images shown in gallery order."
        }
      },
      "required": [
        "type",
        "images"
      ],
      "additionalProperties": false,
      "description": "A themed collection of images. Lightbox-enabled images share navigation within the gallery; caption titles, subtitles, and credits follow the active image.",
      "examples": [
        {
          "type": "gallery",
          "images": [
            {
              "src": "/gallery-study.svg",
              "alt": "Neutral layout study with caption",
              "lightbox": true,
              "caption": {
                "title": "Layout study",
                "subtitle": "A caption and sub-caption in the gallery and lightbox.",
                "credit": "Quail Pages"
              }
            },
            {
              "src": "/gallery-study.svg",
              "alt": "Neutral layout study without caption",
              "lightbox": true
            }
          ]
        }
      ],
      "qpUseWhen": "Use for multiple related images presented together as a gallery."
    },
    "List": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "const": "list",
          "description": "Identifies the Element type represented by this object."
        },
        "class": {
          "type": "string",
          "description": "Optional styling hook."
        },
        "items": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Inline-markup text items rendered in authored order.",
          "minItems": 1
        },
        "ordered": {
          "type": "boolean",
          "description": "Uses an ordered list when enabled."
        }
      },
      "required": [
        "type",
        "items"
      ],
      "additionalProperties": false,
      "description": "An ordered or unordered content list.",
      "examples": [
        {
          "type": "list",
          "items": [
            "Choose a trail.",
            "Pack binoculars.",
            "Start birding."
          ],
          "ordered": true
        }
      ],
      "qpUseWhen": "Use for a semantic sequence or collection."
    },
    "Menu": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "const": "menu",
          "description": "Identifies the Element type represented by this object."
        },
        "class": {
          "type": "string",
          "description": "Optional styling hook."
        },
        "items": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/MenuItem"
          },
          "description": "Items rendered in authored order."
        },
        "ariaLabel": {
          "type": "string",
          "description": "Accessible label for the action or navigation."
        },
        "navId": {
          "type": "string",
          "description": "Stable DOM ID used by menu controls and nested disclosures."
        },
        "mobileCollapse": {
          "type": "boolean",
          "description": "Enables the theme-controlled mobile menu disclosure."
        },
        "search": {
          "type": "object",
          "properties": {
            "placeholder": {
              "type": "string",
              "description": "Search-field placeholder; defaults to `Search`."
            }
          },
          "additionalProperties": false,
          "description": "Optional label search for this menu's authored item tree."
        }
      },
      "required": [
        "type",
        "items"
      ],
      "additionalProperties": false,
      "description": "A navigation menu adapted to its page region. Menu owns the final semantic navigation and link markup, including optional supporting icons.",
      "examples": [
        {
          "type": "menu",
          "ariaLabel": "Example navigation",
          "items": [
            {
              "label": "Search",
              "icon": {
                "name": "search"
              },
              "link": {
                "href": "#search"
              }
            },
            {
              "label": "About",
              "link": {
                "href": "#about"
              }
            }
          ]
        }
      ]
    },
    "MenuItem": {
      "type": "object",
      "properties": {
        "label": {
          "type": "string"
        },
        "link": {
          "$ref": "#/definitions/Link"
        },
        "disclosure": {
          "type": "boolean",
          "description": "Makes this item's nested items interactively collapsible when the item is an organizational label rather than a navigation destination."
        },
        "ariaLabel": {
          "type": "string"
        },
        "icon": {
          "$ref": "#/definitions/Icon",
          "description": "Optional supporting icon rendered before the label."
        },
        "class": {
          "type": "string",
          "description": "Optional styling hook."
        },
        "items": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/MenuItem"
          }
        }
      },
      "required": [
        "label"
      ],
      "additionalProperties": false,
      "description": "A link in an authored navigation menu."
    },
    "Modal": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "type": {
          "type": "string",
          "const": "modal",
          "description": "Identifies the Element type represented by this object."
        },
        "id": {
          "type": "string",
          "description": "Stable fragment target used to address this Modal."
        },
        "title": {
          "type": "string",
          "description": "Visible Modal heading and accessible dialog name."
        },
        "sections": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/PageSection"
          },
          "description": "Normal QP sections rendered as the Modal body."
        },
        "close": {
          "type": "object",
          "properties": {
            "control": {
              "type": "boolean",
              "description": "Shows the visible close control."
            },
            "escape": {
              "type": "boolean",
              "description": "Allows Escape to close the Modal."
            },
            "backdrop": {
              "type": "boolean",
              "description": "Allows the backdrop to close the Modal."
            }
          },
          "additionalProperties": false,
          "description": "Optional dismissal configuration; every behavior defaults to enabled."
        },
        "initialFocus": {
          "type": "string",
          "enum": [
            "close",
            "content"
          ],
          "description": "Preferred initial focus destination; defaults to the close control, then content."
        }
      },
      "required": [
        "id",
        "sections",
        "title",
        "type"
      ],
      "description": "An addressable dialog rendered outside normal document flow.\n\nAny same-document Link whose fragment resolves to this Modal's ID is enhanced by the QP runtime to open it as a dialog.",
      "examples": [
        {
          "type": "modal",
          "id": "qpm-help",
          "title": "Help",
          "sections": [
            {
              "id": "qpm-help-content",
              "title": "Help details",
              "titleSrOnly": true,
              "appearance": "transparent",
              "elements": [
                {
                  "type": "paragraph",
                  "text": "Use any normal QP content inside a Modal."
                }
              ]
            }
          ]
        }
      ],
      "qpRecommend": "Modal IDs should use the `qpm-` prefix to reduce collisions with\nother document IDs and make Modal fragment targets recognizable. The prefix is\nan authoring convention and is not required by the runtime."
    },
    "PageList": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "const": "page-list",
          "description": "Identifies the Element type represented by this object."
        },
        "path": {
          "type": "string",
          "description": "Base site path used for automatic page discovery. Defaults to the current page path when omitted. Ignored when `pages` is provided."
        },
        "pages": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/PageCard"
          },
          "description": "Explicit page references rendered in the authored order. When provided, explicit selection replaces path-based discovery."
        },
        "ctaText": {
          "type": "string",
          "description": "List-wide CTA label for generated page cards. Individual page references may override it with their own CTA text."
        },
        "detail": {
          "type": "object",
          "properties": {
            "field": {
              "type": "string",
              "description": "Dot/path reference to a value in the source page document."
            },
            "format": {
              "type": "string",
              "enum": [
                "date",
                "number",
                "currency"
              ],
              "description": "Optional canonical formatting applied to the resolved scalar value."
            },
            "icon": {
              "$ref": "#/definitions/Icon",
              "description": "Optional icon displayed with the detail value."
            },
            "class": {
              "type": "string",
              "description": "Optional styling hook."
            }
          },
          "required": [
            "field"
          ],
          "additionalProperties": false,
          "description": "Adds a metadata detail row to each generated card by resolving the specified field from that card's page document."
        },
        "pageImageStyle": {
          "type": "string",
          "enum": [
            "default",
            "full-bleed",
            "inset"
          ],
          "description": "Image treatment applied to every generated page card."
        },
        "limit": {
          "type": "number",
          "description": "Maximum number of successfully generated cards. Invalid or non-positive values are ignored."
        },
        "class": {
          "type": "string",
          "description": "Optional styling hook."
        },
        "columns": {
          "type": "number",
          "description": "Requested number of card-grid columns. Valid values are integers from 1 through 4; defaults to 3."
        },
        "recursive": {
          "type": "boolean",
          "description": "Controls path-based discovery. False/omitted selects only direct children of `path`. True includes all descendant pages. Has no effect when `pages` is provided."
        }
      },
      "required": [
        "type"
      ],
      "additionalProperties": false,
      "description": "Generates cards from existing page documents in the site manifest.\n\nPageList is a page-aware convenience primitive. It selects real QP pages, adapts their page content and metadata into cards, and renders the resulting cards through CardList.\n\nPages can be selected in one of two ways:\n\n- Path discovery: omit `pages` and use `path` to select pages beneath a   site path. When `path` is omitted, the current page path is used.   By default only direct children are included; set `recursive` to include   all descendants.\n\n- Explicit selection: provide `pages` to select specific page documents   and control their order. When `pages` is present, path discovery is not used.\n\nEach selected PageDocument remains the source of truth. PageList selects and adapts those pages into normal CardList and Card structures, then delegates final rendering to those existing primitives rather than owning parallel card markup.\n\nPageCard represents an explicit page selection and any selection-local configuration it owns. Each selected page's `pageListItemSettings` may provide page-owned presentation settings such as image, subtitle, description, badge, and CTA text without changing the page's normal presentation.",
      "examples": [
        {
          "type": "page-list",
          "path": "/stories/",
          "recursive": true,
          "limit": 6,
          "columns": 3,
          "detail": {
            "field": "meta.publishDate",
            "format": "date"
          }
        },
        {
          "type": "page-list",
          "pages": [
            {
              "page": "#example",
              "badge": "Featured"
            },
            {
              "page": "#another"
            }
          ],
          "ctaText": "Read story"
        }
      ],
      "qpUseWhen": "Use when cards represent existing QP page documents, especially\nfor indexes, landing pages, related-page collections, or navigation derived\nfrom the site's page structure. Prefer PageList when the page documents\nshould remain the source of truth.",
      "qpAvoidWhen": "Use `card-list` when cards are independent content rather than\nrepresentations of existing pages, or when their content should be authored\ndirectly in the current document."
    },
    "PageCard": {
      "type": "object",
      "properties": {
        "page": {
          "type": "string",
          "description": "Referenced page path."
        },
        "badge": {
          "type": [
            "string",
            "null"
          ],
          "description": "Badge override for this page in this list. Omit or set to `undefined` to use page/default badge behavior. Set to `null` or a blank string to suppress the badge."
        }
      },
      "required": [
        "page"
      ],
      "additionalProperties": false,
      "description": "A page selected for a page list, with presentation overrides local to that list."
    },
    "Paragraph": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "const": "paragraph",
          "description": "Identifies the Element type represented by this object."
        },
        "text": {
          "type": "string",
          "description": "Content rendered through inline markup."
        },
        "class": {
          "type": "string",
          "description": "Optional styling hook."
        },
        "align": {
          "type": "string",
          "enum": [
            "left",
            "center",
            "right",
            "justify"
          ],
          "description": "Controls semantic text alignment.",
          "examples": [
            "center"
          ]
        },
        "tag": {
          "type": "string",
          "enum": [
            "p",
            "div",
            "span",
            "blockquote",
            "h1",
            "h2",
            "h3",
            "h4",
            "h5",
            "h6"
          ],
          "description": "HTML tag used for the block; defaults to `p`."
        },
        "preserveWhitespace": {
          "type": "boolean",
          "description": "Controls whether whitespace is preserved in the rendered output."
        }
      },
      "required": [
        "type",
        "text"
      ],
      "additionalProperties": false,
      "description": "A prose block rendered through QP inline markup.\n\nSupported inline forms are:\n- italics: `++italics++`\n- bold: `**bold**`\n- canonical icons: `^^icon-name^^`, such as `^^icons^^`\n- links: `[inline link text](http://linkaddress.com)`\n- variables: `{{variable.path}}`\n- literal/code text: wrap syntax in backticks, such as `{{variable.path}}`",
      "examples": [
        {
          "type": "paragraph",
          "text": "++Explore++ **together** ^^icons^^ [Join us](https://example.com)"
        }
      ],
      "qpUseWhen": "Use for narrative or explanatory text.",
      "qpAvoidWhen": "The content is a semantic list or action."
    },
    "PluginRef": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "const": "plugin",
          "description": "Selects plugin rendering for this object."
        },
        "plugin": {
          "type": "string",
          "description": "Plugin registration identifier."
        },
        "element": {
          "type": "string",
          "description": "Element identifier owned by the plugin."
        }
      },
      "required": [
        "type",
        "plugin",
        "element"
      ],
      "additionalProperties": {
        "description": "Additional JSON properties passed to and interpreted by the selected plugin."
      },
      "description": "An authored invocation of a registered plugin. Additional invocation fields are owned by the selected plugin.",
      "examples": [
        {
          "type": "plugin",
          "plugin": "example-plugin",
          "element": "featured-content",
          "title": "Featured Content",
          "limit": 3
        }
      ]
    },
    "ProductList": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "type": {
          "type": "string",
          "const": "product-list",
          "description": "Identifies the Element type represented by this object."
        },
        "products": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/ProductCard"
          },
          "description": "Products rendered in authored order."
        },
        "class": {
          "type": "string",
          "description": "Optional styling hook."
        },
        "cardClass": {
          "type": "string",
          "description": "Optional theme styling hook of the individual children cards."
        },
        "columns": {
          "type": "number",
          "description": "Controls the preferred number of cards per row; the grid may use fewer columns when space is limited.",
          "minimum": 1,
          "maximum": 4,
          "multipleOf": 1
        }
      },
      "required": [
        "products",
        "type"
      ],
      "description": "A specialized card list for product content.\n\nShares CardList layout and styling behavior while using ProductCard entries instead of Card entries.",
      "examples": [
        {
          "type": "product-list",
          "columns": 2,
          "products": [
            {
              "name": "Birds of Utah",
              "description": "A field guide to birds found throughout Utah.",
              "price": 399,
              "merchant": "Example Books",
              "link": {
                "href": "https://example.com/birds-of-utah",
                "sponsored": true
              }
            }
          ]
        }
      ],
      "qpUseWhen": "Use when the cards represent products with structured product fields such as price, merchant, image, and CTA.",
      "qpAvoidWhen": "Items are generic content rather than products; use card-list."
    },
    "ProductCard": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string",
          "description": "Product display name.",
          "examples": [
            "Birds of Utah"
          ]
        },
        "price": {
          "type": [
            "string",
            "number"
          ],
          "description": "Product price or pricing information.",
          "examples": [
            399,
            399.95,
            "Call for price",
            "Varies",
            "From $399"
          ]
        },
        "description": {
          "type": "string",
          "description": "Product summary rendered in the card body.",
          "examples": [
            "A field guide to birds found throughout Utah."
          ]
        },
        "link": {
          "$ref": "#/definitions/Link",
          "description": "Product destination.",
          "examples": [
            {
              "href": "https://example.com/product",
              "newTab": true
            }
          ]
        },
        "ctaText": {
          "type": "string",
          "description": "Product action label; defaults to `View on {merchant}` when a merchant is provided.",
          "examples": [
            "View on Amazon"
          ]
        },
        "ctaAriaLabel": {
          "type": "string",
          "description": "Accessible product action label; defaults to the action label and product name.",
          "examples": [
            "View on Amazon: Birds of Utah"
          ]
        },
        "merchant": {
          "type": "string",
          "description": "Merchant offering the product.",
          "examples": [
            "Amazon"
          ]
        },
        "image": {
          "$ref": "#/definitions/Image",
          "description": "Image used by the owning object."
        }
      },
      "additionalProperties": false,
      "description": "Product information adapted into a card."
    },
    "Socials": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "const": "socials",
          "description": "Identifies the Element type represented by this object."
        },
        "class": {
          "type": "string",
          "description": "Optional styling hook."
        },
        "keys": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Keys in the site's `socials` map."
        },
        "ariaLabel": {
          "type": "string",
          "description": "Accessible label for the action or navigation."
        }
      },
      "required": [
        "type",
        "keys"
      ],
      "additionalProperties": false,
      "description": "Built Content that selects reusable site social definitions, adapts them to icon-based MenuItems, and delegates final navigation rendering to Menu.",
      "examples": [
        {
          "type": "socials",
          "keys": [
            "community"
          ],
          "ariaLabel": "Community links"
        }
      ]
    },
    "StickyTray": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "const": "sticky-tray",
          "description": "Identifies the StickyTray type represented by this object."
        },
        "id": {
          "type": "string",
          "description": "Stable non-empty identifier used to associate the tray control and content panel.",
          "minLength": 1
        },
        "ariaLabel": {
          "type": "string",
          "description": "Accessible name for the tray container."
        },
        "handle": {
          "type": "object",
          "properties": {
            "elements": {
              "type": "array",
              "items": {
                "$ref": "#/definitions/Element"
              },
              "description": "Menus, cards, images, or other ordinary Elements in the persistent handle."
            },
            "class": {
              "type": "string",
              "description": "Optional styling hook for the handle content."
            }
          },
          "required": [
            "elements"
          ],
          "additionalProperties": false,
          "description": "Persistent content, rendered independently from the panel disclosure button."
        },
        "sections": {
          "type": "array",
          "items": {
            "anyOf": [
              {
                "$ref": "#/definitions/StandardSection"
              },
              {
                "$ref": "#/definitions/RegionSection"
              }
            ]
          },
          "description": "Interior Sections. Omit or leave empty for a permanent handle without a disclosure."
        },
        "disclosure": {
          "type": "string",
          "enum": [
            "none",
            "handle",
            "chevron"
          ],
          "description": "Panel interaction, independent from visibilityTriggers and positionMode. `none` keeps any panel content visible with no disclosure control. `handle` makes the full handle surface toggle the panel; authored links and controls inside the handle keep their own actions. `chevron` uses a separate disclosure button. A tray without panel sections has no disclosure in any mode.",
          "default": "handle"
        },
        "positionMode": {
          "type": "string",
          "enum": [
            "overlay",
            "inset"
          ],
          "description": "Overlay leaves the document viewport unchanged. Inset reserves the measured handle at the top or bottom edge; its panel overlays the remaining viewport. Inset requires top or bottom vertical placement and fills that edge.",
          "default": "overlay"
        },
        "visibilityTriggers": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/StickyTrayTriggerGroup"
          },
          "description": "Conditions controlling when the tray is presented. Trigger values within each inner group use OR; the outer groups use AND. Omit this property for an unconditionally available tray. These conditions control tray visibility, not panel expansion: use disclosure for the panel interaction. Groups and trigger values within each group must be nonempty, and values within a group must be unique.",
          "minItems": 1
        },
        "vertical": {
          "type": "string",
          "enum": [
            "top",
            "middle",
            "bottom"
          ],
          "description": "Vertical viewport placement. Defaults to `top` when omitted. `top` anchors the tray to the top side, `middle` centers it vertically, and `bottom` anchors it to the bottom side.",
          "default": "top"
        },
        "horizontal": {
          "type": "string",
          "enum": [
            "left",
            "center",
            "right"
          ],
          "description": "Horizontal viewport placement. Defaults to `center` when omitted. `left` aligns the tray to the available left side, `center` centers it, and `right` aligns it to the available right side.",
          "default": "center"
        },
        "class": {
          "type": "string",
          "description": "Optional theme styling hook."
        }
      },
      "required": [
        "type",
        "id",
        "ariaLabel",
        "handle"
      ],
      "additionalProperties": false,
      "description": "An authored viewport-persistent content tray.\n\nStickyTray may be authored as an Element or directly as a PageSection. Its authored location establishes an anchor in document flow, while Quail Pages owns the tray markup, accessibility, viewport placement, visibility, and runtime state. The handle renders Elements; the panel renders ordinary Sections. Handle content and its disclosure button are separate interactive surfaces.\n\nWhen `visibilityTriggers` is omitted, the tray is simply available. Within each trigger group, any trigger may satisfy the group (OR). Every group must be satisfied for the tray to be presented (AND). Responsive triggers use the canonical QP mobile, tablet, and desktop presentation-width ranges. Anchor triggers are evaluated against the tray's authored anchor: `anchor-passed` becomes true after the anchor crosses above the viewport start, `anchor-visible` is true while any part of the anchor is inside the viewport, and `anchor-passed-center` becomes true after the anchor crosses above the viewport center line. Authored location alone enables no visibility trigger.\n\nVertical and horizontal placement independently control where the active tray appears and default to top-center. Overlay placement accounts for occupied header/footer boundaries. Inset fills the top or bottom edge, independently of horizontal alignment, and reserves its measured handle in the document viewport. Multiple inset handles stack in authored order. The panel overlays the remaining viewport. Inset shells move to the document viewport; authored anchors stay put.\n\nThree independent choices: `disclosure` controls panel interaction; `visibilityTriggers` controls when the whole tray appears; `positionMode` controls whether it reserves viewport space. For a permanent sticky menu, author the menu in handle.elements with no sections and omit visibilityTriggers. To show that menu only after scrolling past its authored position, add visibilityTriggers: [[\"anchor-passed\"]]. No disclosure button is needed.",
      "examples": [
        {
          "type": "sticky-tray",
          "id": "quick-links",
          "ariaLabel": "Quick links",
          "handle": {
            "elements": [
              {
                "type": "paragraph",
                "text": "^^☰^^ Quick links"
              }
            ]
          },
          "sections": [
            {
              "id": "quick-links-content",
              "title": "Quick links",
              "titleSrOnly": true,
              "appearance": "transparent",
              "elements": [
                {
                  "type": "menu",
                  "ariaLabel": "Quick links",
                  "items": [
                    {
                      "label": "Example",
                      "link": {
                        "href": "#example"
                      }
                    }
                  ]
                }
              ]
            }
          ]
        },
        {
          "type": "sticky-tray",
          "id": "page-navigation",
          "ariaLabel": "Page navigation",
          "visibilityTriggers": [
            [
              "mobile",
              "tablet"
            ],
            [
              "anchor-passed"
            ]
          ],
          "handle": {
            "elements": [
              {
                "type": "paragraph",
                "text": "^^☰^^ Page navigation"
              }
            ]
          },
          "sections": [
            {
              "id": "page-navigation-content",
              "title": "Page navigation",
              "titleSrOnly": true,
              "appearance": "transparent",
              "elements": [
                {
                  "type": "menu",
                  "ariaLabel": "Page navigation",
                  "items": [
                    {
                      "label": "Example",
                      "link": {
                        "href": "#example"
                      }
                    }
                  ]
                }
              ]
            }
          ]
        }
      ],
      "qpUseWhen": "Content should remain available in a persistent handle, optionally\nwith a designed panel, such as navigation or contextual page controls.",
      "qpAvoidWhen": "Content belongs directly in the normal section flow without\npersistent access while scrolling."
    },
    "RegionSection": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "regions": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/Region"
          },
          "description": "Independently sized content regions."
        },
        "maxPerRow": {
          "type": "number",
          "description": "Maximum regions in each row.",
          "minimum": 1,
          "multipleOf": 1
        },
        "type": {
          "type": "string",
          "const": "section",
          "description": "Identifies this as a standard content section."
        },
        "id": {
          "type": "string",
          "description": "Stable document, section, or region identifier."
        },
        "title": {
          "type": "string",
          "description": "Semantic section heading."
        },
        "titleSrOnly": {
          "type": "boolean",
          "description": "Renders the section heading visually hidden but available to screen readers."
        },
        "subtitle": {
          "type": "string",
          "description": "Supporting text associated with the heading."
        },
        "width": {
          "type": "string",
          "enum": [
            "default",
            "wide",
            "full",
            "theme"
          ],
          "description": "Standard section width treatment. Defaults to `default` when omitted. `default` uses the standard constrained content width with normal outer breathing room. `wide` uses a wider constrained content width while retaining normal outer breathing room. `full` is a full-bleed treatment whose section surface extends edge-to-edge without an outer inline gutter or corner treatment by default; use it for backgrounds, imagery, media, and other continuous surfaces. Child content may remain independently constrained. `theme` applies no standard width treatment; the authored `class` and active theme own the width behavior.",
          "default": "default"
        },
        "appearance": {
          "type": "string",
          "enum": [
            "default",
            "alternate",
            "transparent",
            "theme"
          ],
          "description": "Standard section surface treatment. Defaults to `default` when omitted. `default` uses the standard Base/theme section surface. `alternate` uses the standard visually distinct alternate surface while retaining normal section structure. `transparent` removes the standard section surface so the surrounding page or background shows through while retaining normal section structure. `theme` emits no standard appearance class and opts out of the complete standard Section surface recipe. The authored `class` and active theme own its background, foreground, internal padding, border, radius, shadow, and other surface behavior. Use it to replace the standard composition rather than merely recolor it. When the custom appearance creates a visible surface boundary, the theme must provide an appropriate internal inset; it may explicitly reuse the standard Section surface padding variables.",
          "default": "default"
        },
        "class": {
          "type": "string",
          "description": "Optional styling hook."
        }
      },
      "required": [
        "id",
        "regions",
        "title"
      ],
      "description": "A section arranging content into rows of regions.",
      "qpUseWhen": "Use when a section requires multiple independently sized content areas, such as side-by-side text/media, asymmetric columns, or multi-column layouts that cannot be expressed by a purpose-built collection primitive."
    },
    "Region": {
      "type": "object",
      "properties": {
        "class": {
          "type": "string",
          "description": "Optional space-separated classes added to the qp-region wrapper for theme-owned semantic roles, such as qp-region--reference-nav or qp-region--example-rail. Use relativeWidth and newRow for the normal Region layout contract.",
          "examples": [
            "qp-region--content"
          ]
        },
        "elements": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/Element"
          },
          "description": "Elements rendered in authored order."
        },
        "relativeWidth": {
          "type": "number",
          "description": "Width share relative to sibling regions.",
          "minimum": 1
        },
        "newRow": {
          "type": "boolean",
          "description": "Starts this region on a new row."
        }
      },
      "required": [
        "elements"
      ],
      "additionalProperties": false,
      "description": "An independently sized layout region within a section. Regions intentionally provide no default surface padding. Region gaps separate sibling Regions and do not replace the owning Section's internal surface inset."
    },
    "StickyTrayTriggerGroup": {
      "type": "array",
      "items": {
        "type": "string",
        "enum": [
          "mobile",
          "tablet",
          "desktop",
          "anchor-passed",
          "anchor-visible",
          "anchor-passed-center"
        ]
      },
      "description": "A nonempty set of unique StickyTray visibility triggers combined with OR semantics.",
      "minItems": 1,
      "uniqueItems": true
    },
    "Toc": {
      "type": "object",
      "properties": {
        "sticky": {
          "type": "boolean",
          "description": "Renders the table of contents using the StickyTray presentation.\n\nDefaults to true."
        },
        "card": {
          "type": "boolean",
          "description": "Renders an in-flow Card presentation of the table of contents.\n\nDefaults to false."
        },
        "type": {
          "type": "string",
          "const": "toc",
          "description": "Identifies the Element type represented by this object."
        },
        "class": {
          "type": "string",
          "description": "Optional styling hook."
        }
      },
      "required": [
        "type"
      ],
      "additionalProperties": false,
      "description": "A page-aware table of contents generated automatically from eligible sections in the current page.\n\nToc is a specialized composition rather than a standalone rendering primitive. It derives its navigation from the page and uses shared QP primitives to present that navigation consistently.\n\nBy default, Toc renders as a position-aware StickyTray. It can also render an in-flow Card presentation. When placed inside a compatible container, the renderer may reuse the container supplied by its parent rather than emitting a redundant wrapper.",
      "examples": [
        {
          "type": "toc",
          "sticky": false,
          "card": true
        },
        {
          "type": "toc"
        },
        {
          "type": "toc",
          "card": true
        }
      ]
    },
    "Video": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "const": "video",
          "description": "Identifies the Element type represented by this object."
        },
        "class": {
          "type": "string",
          "description": "Optional styling hook."
        },
        "provider": {
          "type": "string",
          "enum": [
            "youtube",
            "vimeo"
          ],
          "description": "Hosting service used for the embed."
        },
        "videoId": {
          "type": "string",
          "description": "Provider-specific video identifier."
        },
        "startSeconds": {
          "type": "number",
          "description": "Playback offset; invalid or negative values are ignored."
        },
        "privacyMode": {
          "type": "boolean",
          "description": "Uses YouTube's privacy-enhanced host; defaults on."
        },
        "aspectRatio": {
          "type": "string",
          "description": "Player proportions; unsupported values use `16:9`."
        },
        "image": {
          "type": "object",
          "properties": {
            "src": {
              "type": "string",
              "description": "Image URL or site-relative path."
            },
            "alt": {
              "type": "string",
              "description": "Accessible text alternative."
            },
            "width": {
              "type": "number",
              "description": "Maximum responsive source width."
            },
            "caption": {
              "type": "object",
              "properties": {
                "title": {
                  "type": "string",
                  "description": "Visible heading or display name."
                },
                "subtitle": {
                  "type": "string",
                  "description": "Supporting text associated with the heading."
                },
                "credit": {
                  "type": "string",
                  "description": "Image credit text."
                }
              },
              "additionalProperties": false,
              "description": "Structured media caption."
            }
          },
          "required": [
            "src",
            "alt"
          ],
          "additionalProperties": false,
          "description": "Image used by the owning object."
        }
      },
      "required": [
        "type",
        "provider",
        "videoId",
        "image"
      ],
      "additionalProperties": false,
      "description": "An embedded video launched from a poster image.",
      "examples": [
        {
          "type": "video",
          "provider": "youtube",
          "videoId": "krk8RCREK38",
          "image": {
            "src": "/gallery-study.svg",
            "alt": "Neutral poster for the Merlin Bird ID guide",
            "caption": {
              "title": "Master Merlin Bird ID",
              "subtitle": "A video poster with a structured caption."
            }
          }
        }
      ]
    },
    "SiteFooter": {
      "type": "object",
      "properties": {
        "sections": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/PageSection"
          },
          "description": "Sections rendered in authored order within the site footer."
        }
      },
      "required": [
        "sections"
      ],
      "additionalProperties": false,
      "description": "Site-wide footer content organized into authored sections.",
      "examples": [
        {
          "sections": [
            {
              "id": "footer-navigation",
              "title": "Footer navigation",
              "elements": [
                {
                  "type": "menu",
                  "class": "qp-menu--footer",
                  "navId": "qp-footer-menu",
                  "ariaLabel": "Footer navigation",
                  "items": [
                    {
                      "label": "About",
                      "link": {
                        "href": "/about/"
                      }
                    },
                    {
                      "label": "Privacy",
                      "link": {
                        "href": "/privacy/"
                      }
                    }
                  ]
                }
              ]
            }
          ]
        }
      ],
      "qpUseWhen": "Use for content that should appear in the site's footer across pages.",
      "qpAvoidWhen": "The content is an endcap, disclosure, navigation block, or call to action used only by selected pages; use a reusable component instead."
    },
    "SiteSocials": {
      "type": "object",
      "additionalProperties": {
        "$ref": "#/definitions/SiteSocial"
      },
      "description": "Reusable social destinations keyed by the names referenced by authored social and invitation elements.",
      "qpUseWhen": "Define site-wide social destinations for reuse by authored elements."
    },
    "SiteSocial": {
      "type": "object",
      "properties": {
        "label": {
          "type": "string",
          "description": "Visible or accessible link label."
        },
        "link": {
          "$ref": "#/definitions/Link",
          "description": "Social destination."
        },
        "icon": {
          "$ref": "#/definitions/Icon",
          "description": "Supporting icon used when this destination is adapted into navigation."
        }
      },
      "required": [
        "label",
        "link",
        "icon"
      ],
      "additionalProperties": false,
      "description": "A reusable social destination.",
      "examples": [
        {
          "label": "Facebook",
          "link": {
            "href": "https://www.facebook.com/example",
            "newTab": true,
            "nofollow": true
          },
          "icon": {
            "name": "facebook"
          }
        }
      ],
      "qpUseWhen": "Define a social destination once when it will be referenced by socials or invite elements.",
      "qpAvoidWhen": "The link is ordinary navigation or a one-off page action."
    },
    "SiteAuthors": {
      "type": "object",
      "additionalProperties": {
        "$ref": "#/definitions/SiteAuthor"
      },
      "description": "Site-level author profiles keyed by the display names used in page metadata.",
      "examples": [
        {
          "Jane Smith": {
            "profileUrl": "/authors/jane-smith/"
          },
          "John Doe": {
            "profileUrl": "/authors/john-doe/"
          }
        }
      ],
      "qpUseWhen": "Enrich one or more page-authored author names with shared profile information."
    },
    "SiteAuthor": {
      "type": "object",
      "properties": {
        "profileUrl": {
          "type": "string",
          "description": "Canonical author profile URL."
        }
      },
      "required": [
        "profileUrl"
      ],
      "additionalProperties": false,
      "description": "A site-level author profile used to enrich a page-authored author name.",
      "examples": [
        {
          "profileUrl": "/authors/jane-smith/"
        }
      ],
      "qpUseWhen": "Use when an author named in page metadata should resolve to additional site-wide profile information.",
      "qpAvoidWhen": "Only the author's display name is needed; `meta.author` can stand alone without a matching site author definition."
    },
    "PageDocument": {
      "type": "object",
      "properties": {
        "pageTitle": {
          "type": "string",
          "description": "Browser and metadata title for the page.\n\nUsed as the canonical page title for browser, search, social, and structured metadata. Visible heading presentation is owned separately by `pageHeader`.",
          "qpRecommend": "Supply a focused title for indexable production pages."
        },
        "pageHeader": {
          "$ref": "#/definitions/PageHeader",
          "description": "Visible page heading presentation."
        },
        "description": {
          "type": "string",
          "description": "Summary used by search, social, and structured metadata.",
          "minLength": 70,
          "maxLength": 155,
          "qpRecommend": "Supply a useful description between 70 and 155 characters\nfor indexable production pages."
        },
        "pageListItemSettings": {
          "$ref": "#/definitions/PageListItemSettings",
          "description": "Page-owned presentation settings used when this page appears in PageList.\n\nThese values are used only when this page is represented as a generated card by PageList. They allow the card representation to differ from the page's normal title, description, hero, and other page presentation without changing the page itself."
        },
        "meta": {
          "type": "object",
          "properties": {
            "socialImage": {
              "$ref": "#/definitions/Image",
              "description": "Explicit image for social and Open Graph metadata. When omitted, QP derives the image from the page Hero, the first eligible authored content image, or the site's publisher logo."
            },
            "publishDate": {
              "type": "string",
              "description": "Date the page was originally published."
            },
            "updateDate": {
              "type": "string",
              "description": "Date of the most recent meaningful content update."
            },
            "location": {
              "type": "string",
              "description": "Location where the page's subject or event occurred."
            },
            "noIndex": {
              "type": "boolean",
              "description": "Excludes the page from indexing-oriented output and listings by default."
            },
            "noRss": {
              "type": "boolean",
              "description": "Excludes the page from RSS output."
            },
            "author": {
              "type": "string",
              "description": "Author display name and optional key into the site's `authors` definitions. If no matching site author exists, this value is still used as the author name."
            }
          },
          "additionalProperties": false,
          "description": "Metadata used by discovery and derived artifacts."
        },
        "type": {
          "type": "string",
          "description": "Page classification used for routing, metadata, and page-aware integrations."
        },
        "id": {
          "type": "string",
          "description": "Stable document, section, or region identifier."
        },
        "class": {
          "type": "string",
          "description": "Optional styling hook."
        },
        "sections": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/PageSection"
          },
          "description": "Sections forming the page body."
        }
      },
      "required": [
        "pageTitle",
        "pageHeader",
        "id",
        "sections"
      ],
      "additionalProperties": false,
      "description": "A persisted Quail Pages page document.\n\nPage documents define the content and metadata for individual pages in a Quail Pages site. They are conventionally stored beneath the site's `pages/` directory. Each `SiteDocument.pages[].source` is relative to that directory.\n\nA page document's source location does not determine its public URL. `SiteDocument.pages[].path` explicitly maps each authored page source to its public URL, allowing source organization and website routing to remain independent.",
      "qpUseWhen": "Use as the root of an authored page JSON file beneath `pages/`.",
      "qpAvoidWhen": "Defining site-wide configuration or reusable content; use a\nSiteDocument or Component instead."
    },
    "PageHeader": {
      "type": "object",
      "properties": {
        "title": {
          "type": "string",
          "description": "Visible page heading."
        },
        "subtitle": {
          "type": "string",
          "description": "Optional supporting text displayed with the page heading."
        },
        "hero": {
          "$ref": "#/definitions/Image",
          "description": "Optional hero media that selects the full-bleed PageHeader presentation."
        }
      },
      "required": [
        "title"
      ],
      "additionalProperties": false,
      "description": "Visible page-level heading presentation.\n\nWithout `hero`, PageHeader renders a conventional heading aligned to the standard contained page grid. Supplying `hero` selects the explicit hero breakout: media may extend full bleed while the heading panel remains independently constrained by the active theme.",
      "examples": [
        {
          "title": "Birding in Utah",
          "subtitle": "Field notes and practical guides",
          "hero": {
            "src": "/images/utah-birds.jpg",
            "alt": "Birds above a Utah wetland"
          }
        }
      ]
    },
    "PageListItemSettings": {
      "type": "object",
      "properties": {
        "image": {
          "$ref": "#/definitions/Image",
          "description": "Image shown instead of the page hero in generated PageList cards."
        },
        "subtitle": {
          "type": "string",
          "description": "Subtitle shown for this page in generated PageList cards."
        },
        "badge": {
          "type": [
            "string",
            "null"
          ],
          "description": "Overrides the badge shown on generated PageList cards. When omitted or `undefined`, the page author is used as the default badge. Set to `null` or an empty string to suppress the default badge."
        },
        "description": {
          "type": "string",
          "description": "Summary shown instead of the page description in generated PageList cards."
        },
        "ctaText": {
          "type": "string",
          "description": "Action label shown instead of the owning PageList's `ctaText` default."
        }
      },
      "additionalProperties": false,
      "description": "Page-owned presentation settings used when a page is represented by PageList.\n\nPageListItemSettings is not a standalone Element, Card, or PageCard. It belongs to the owning PageDocument and affects only that page's generated PageList representation. It allows a page to present differently inside a PageList without changing the page's normal presentation.\n\nOmitted values fall back to the page's normal content or the owning PageList's defaults according to PageList's existing precedence rules."
    },
    "Component": {
      "anyOf": [
        {
          "$ref": "#/definitions/PageSection"
        },
        {
          "type": "array",
          "items": {
            "$ref": "#/definitions/Element"
          }
        }
      ],
      "description": "Persisted reusable Quail Pages component content.\n\nComponents are conventionally stored beneath the site's `components/` directory and are referenced from pages or other supported authored structures. They are not rendered as standalone pages.\n\nA component may contain either:\n- one complete page section for section-level reuse, or\n- an ordered list of page elements for element-level reuse.\n\nAt render time, a section-level component must be a complete standard or region-based section with an id and exactly one of `elements` or `regions`. Element-level component content must remain an array, including when it contains only one element.\n\nComponents are a single level of persisted reuse. Component content may not contain ComponentRef values, so components cannot compose, recursively reference themselves, or participate in indirect reference cycles.",
      "examples": [
        {
          "type": "section",
          "id": "shared-endcap",
          "title": "Keep Exploring",
          "titleSrOnly": true,
          "elements": [
            {
              "type": "paragraph",
              "text": "Explore more resources."
            },
            {
              "type": "cta",
              "link": {
                "href": "/resources/"
              },
              "text": "View Resources",
              "ariaLabel": "View more resources"
            }
          ]
        }
      ],
      "qpUseWhen": "Use when the same section or element group should appear in\nmultiple places, such as shared endcaps, disclosures, navigation blocks,\nor calls to action.",
      "qpAvoidWhen": "The content is unique to one page, should be independently\naddressable as a page, or belongs globally in the site header or footer."
    },
    "ModalDefinition": {
      "type": "object",
      "properties": {
        "title": {
          "type": "string",
          "description": "Visible Modal heading and accessible dialog name."
        },
        "sections": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/PageSection"
          },
          "description": "Normal QP sections rendered as the Modal body."
        },
        "close": {
          "type": "object",
          "properties": {
            "control": {
              "type": "boolean",
              "description": "Shows the visible close control."
            },
            "escape": {
              "type": "boolean",
              "description": "Allows Escape to close the Modal."
            },
            "backdrop": {
              "type": "boolean",
              "description": "Allows the backdrop to close the Modal."
            }
          },
          "additionalProperties": false,
          "description": "Optional dismissal configuration; every behavior defaults to enabled."
        },
        "initialFocus": {
          "type": "string",
          "enum": [
            "close",
            "content"
          ],
          "description": "Preferred initial focus destination; defaults to the close control, then content."
        }
      },
      "required": [
        "title",
        "sections"
      ],
      "additionalProperties": false,
      "description": "Content and dismissal configuration shared by authored and programmatic Modals.",
      "qpUseWhen": "Use as the reusable definition passed to the shared Modal renderer."
    }
  }
}
