<?xml version="1.0" encoding="UTF-8"?>
<!--
  gestures.rng — RELAX NG schema (XML syntax) for In the Gesture monthly files
  (gestures/YYYY-MM.xml). Validated against June–September 2026.
-->
<grammar xmlns="http://relaxng.org/ns/structure/1.0"
         datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">

  <start>
    <element name="gestures">
      <oneOrMore>
        <ref name="gesture"/>
      </oneOrMore>
    </element>
  </start>

  <!-- A gesture: when, where, toward which works (if any), then content. -->
  <define name="gesture">
    <element name="gesture">
      <ref name="time"/>
      <ref name="place"/>
      <zeroOrMore>
        <ref name="toward"/>
      </zeroOrMore>
      <oneOrMore>
        <choice>
          <ref name="image"/>
          <ref name="video"/>
          <ref name="figure"/>
          <ref name="text"/>
        </choice>
      </oneOrMore>
    </element>
  </define>

  <!-- ===== Header ===== -->

  <!-- Full xsd:dateTime with seconds and a required offset:
       2026-09-02T15:57:00-04:00. xsd:dateTime alone leaves the zone
       optional; the pattern makes it mandatory. -->
  <define name="time">
    <element name="time">
      <data type="dateTime">
        <param name="pattern">.+T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+\-]\d{2}:\d{2})</param>
      </data>
    </element>
  </define>

  <define name="place">
    <element name="place">
      <data type="token">
        <param name="minLength">1</param>
      </data>
    </element>
  </define>

  <!-- A work id. Whether it exists in works.xml is Schematron's job. -->
  <define name="toward">
    <element name="toward">
      <ref name="work-id"/>
    </element>
  </define>

  <define name="work-id">
    <data type="token">
      <param name="pattern">[a-z0-9]+(-[a-z0-9]+)*</param>
    </data>
  </define>

  <!-- ===== Media ===== -->

  <!-- Bare filenames, resolved against captures/. No paths, no spaces. -->
  <define name="image-filename">
    <data type="token">
      <param name="pattern">[^/\\\s]+\.(jpg|jpeg|png|webp|gif)</param>
    </data>
  </define>

  <define name="video-filename">
    <data type="token">
      <param name="pattern">[^/\\\s]+\.(mp4|webm|mov)</param>
    </data>
  </define>

  <define name="image">
    <element name="image">
      <element name="file"><ref name="image-filename"/></element>
      <optional><ref name="caption"/></optional>
    </element>
  </define>

  <define name="video">
    <element name="video">
      <element name="file"><ref name="video-filename"/></element>
      <optional><ref name="caption"/></optional>
    </element>
  </define>

  <!-- Documentation of a finished work, gathered onto that work's page. -->
  <define name="figure">
    <element name="figure">
      <element name="work"><ref name="work-id"/></element>
      <element name="file">
        <choice>
          <group>
            <element name="name"><ref name="image-filename"/></element>
            <element name="type"><value>image</value></element>
          </group>
          <group>
            <element name="name"><ref name="video-filename"/></element>
            <element name="type"><value>video</value></element>
          </group>
        </choice>
      </element>
    </element>
  </define>

  <define name="caption">
    <element name="caption">
      <ref name="inline"/>
    </element>
  </define>

  <!-- ===== Prose ===== -->

  <define name="text">
    <element name="text">
      <oneOrMore>
        <choice>
          <ref name="p"/>
          <ref name="blockquote"/>
        </choice>
      </oneOrMore>
    </element>
  </define>

  <define name="blockquote">
    <element name="blockquote">
      <oneOrMore>
        <ref name="p"/>
      </oneOrMore>
    </element>
  </define>

  <define name="p">
    <element name="p">
      <ref name="inline"/>
    </element>
  </define>

  <!-- Inline: text with <i> (titles, foreign words), <em> (emphasis),
       and <br/> (verse lines). -->
  <define name="inline">
    <mixed>
      <zeroOrMore>
        <choice>
          <element name="i"><ref name="inline"/></element>
          <element name="em"><ref name="inline"/></element>
          <element name="br"><empty/></element>
        </choice>
      </zeroOrMore>
    </mixed>
  </define>

</grammar>
