{
  "schemaVersion": 1,
  "packageVersion": "1.99.0",
  "components": [
    {
      "kind": "component",
      "id": "accordion",
      "capabilities": [
        "expand",
        "select_single",
        "select_multiple"
      ],
      "state": [
        {
          "name": "openItems",
          "type": "string[]",
          "description": "Ids (values) of currently-expanded items. Single-mode accordions return an array with 0 or 1 entries.",
          "descriptionKey": "ui.agent.accordion.state.openItems"
        }
      ],
      "actions": [
        {
          "name": "expand",
          "safety": "read",
          "argsType": "{ itemId: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "itemId": {
                "type": "string"
              }
            },
            "required": [
              "itemId"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "itemId": "billing"
              },
              "note": "Expand the \"billing\" panel."
            }
          ],
          "description": "Expand the item with the given value.",
          "descriptionKey": "ui.agent.accordion.actions.expand"
        },
        {
          "name": "collapse",
          "safety": "read",
          "argsType": "{ itemId: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "itemId": {
                "type": "string"
              }
            },
            "required": [
              "itemId"
            ]
          },
          "idempotent": true,
          "description": "Collapse the item with the given value.",
          "descriptionKey": "ui.agent.accordion.actions.collapse"
        },
        {
          "name": "clear",
          "safety": "read",
          "idempotent": true,
          "description": "Collapse all items. Only meaningful for multi-mode accordions; single-mode equivalent to collapsing the active item.",
          "descriptionKey": "ui.agent.accordion.actions.clear"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "accordion"
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        },
        "item": {
          "attr": "data-item-id",
          "description": "Each Accordion.Item emits its value as data-item-id."
        }
      }
    },
    {
      "kind": "component",
      "id": "address-autocomplete",
      "capabilities": [
        "select_single",
        "filter",
        "open",
        "close"
      ],
      "state": [
        {
          "name": "value",
          "type": "string",
          "description": "Current free-text value of the address input.",
          "descriptionKey": "ui.agent.addressAutocomplete.state.value"
        },
        {
          "name": "query",
          "type": "string",
          "description": "Current query driving the suggestion listbox.",
          "descriptionKey": "ui.agent.addressAutocomplete.state.query"
        },
        {
          "name": "isOpen",
          "type": "boolean",
          "description": "True when the suggestion listbox is visible.",
          "descriptionKey": "ui.agent.addressAutocomplete.state.isOpen"
        }
      ],
      "actions": [
        {
          "name": "set_value",
          "safety": "write",
          "argsType": "{ value: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "value": {
                "type": "string",
                "description": "Text to place in the input (also runs a fetch)."
              }
            },
            "required": [
              "value"
            ]
          },
          "idempotent": true,
          "openWorld": true,
          "examples": [
            {
              "args": {
                "value": "Via Roma 12"
              },
              "note": "Seed a partial address."
            }
          ],
          "description": "Set the input text programmatically; opens and refreshes the suggestion list (issues an external address-lookup fetch).",
          "descriptionKey": "ui.agent.addressAutocomplete.actions.setValue"
        },
        {
          "name": "apply_filter",
          "safety": "read",
          "argsType": "{ query: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "query": {
                "type": "string",
                "description": "Query text to filter the address suggestions."
              }
            },
            "required": [
              "query"
            ]
          },
          "idempotent": true,
          "openWorld": true,
          "description": "Set the query text, which refreshes the suggestion list via an external address-lookup fetch.",
          "descriptionKey": "ui.agent.addressAutocomplete.actions.applyFilter"
        },
        {
          "name": "clear",
          "safety": "write",
          "idempotent": true,
          "description": "Clear the typed text and dismiss the suggestion list.",
          "descriptionKey": "ui.agent.addressAutocomplete.actions.clear"
        },
        {
          "name": "open",
          "safety": "read",
          "idempotent": true,
          "description": "Open the suggestion listbox.",
          "descriptionKey": "ui.agent.addressAutocomplete.actions.open"
        },
        {
          "name": "close",
          "safety": "read",
          "idempotent": true,
          "description": "Close the suggestion listbox.",
          "descriptionKey": "ui.agent.addressAutocomplete.actions.close"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "address-autocomplete",
          "description": "Marks the AddressAutocomplete wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop. Required to address a specific field from the agent."
        }
      }
    },
    {
      "kind": "component",
      "id": "address-fields",
      "capabilities": [
        "set_value"
      ],
      "state": [
        {
          "name": "value",
          "type": "object",
          "description": "The current structured address: { street, city, postcode, province, country, formatted }.",
          "descriptionKey": "ui.agent.addressFields.state.value"
        }
      ],
      "actions": [
        {
          "name": "set_value",
          "safety": "write",
          "argsType": "{ value: StructuredAddress }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "value": {
                "type": "object",
                "properties": {
                  "street": {
                    "type": "string"
                  },
                  "city": {
                    "type": "string"
                  },
                  "postcode": {
                    "type": "string"
                  },
                  "province": {
                    "type": "string",
                    "description": "UPPERCASED province code."
                  },
                  "country": {
                    "type": "string",
                    "description": "ISO alpha-2, lowercased."
                  },
                  "formatted": {
                    "type": "string"
                  }
                }
              }
            },
            "required": [
              "value"
            ]
          },
          "idempotent": true,
          "description": "Replace the entire address.",
          "descriptionKey": "ui.agent.addressFields.actions.setValue"
        },
        {
          "name": "set_field",
          "safety": "write",
          "argsType": "{ field: 'street' | 'city' | 'postcode' | 'province' | 'country'; value: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "street",
                  "city",
                  "postcode",
                  "province",
                  "country"
                ]
              },
              "value": {
                "type": "string"
              }
            },
            "required": [
              "field",
              "value"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "field": "country",
                "value": "it"
              },
              "note": "Set the country to Italy."
            }
          ],
          "description": "Set a single address field. Setting `country` also clears the now-stale province.",
          "descriptionKey": "ui.agent.addressFields.actions.setField"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "address-fields"
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "agenda-card",
      "capabilities": [
        "pick"
      ],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "agenda-card",
          "description": "Marks the element as a kit AgendaCard. The card root also emits data-component-id sourced from item.id and data-status with the appointment lifecycle."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "item.id",
          "description": "Sourced from item.id — the stable appointment identifier."
        }
      }
    },
    {
      "kind": "component",
      "id": "agenda-tray",
      "capabilities": [
        "pick"
      ],
      "state": [
        {
          "name": "items",
          "type": "Array<{ id: string; status: string }>",
          "description": "Currently-displayed appointments. Ids + status only — never patient identity.",
          "descriptionKey": "ui.agent.agendaTray.state.items"
        }
      ],
      "actions": [
        {
          "name": "select_item",
          "safety": "read",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              }
            },
            "required": [
              "id"
            ]
          },
          "examples": [
            {
              "args": {
                "id": "appt-204"
              },
              "note": "Open appointment appt-204."
            }
          ],
          "description": "Activate the appointment with the given id.",
          "descriptionKey": "ui.agent.agendaTray.actions.selectItem"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "agenda-tray",
          "description": "Marks the AgendaTray wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop. Required to address a specific tray from the agent."
        },
        "item": {
          "attr": "data-appointment-id",
          "description": "Stable appointment id emitted on each rendered AgendaCard inside the tray."
        }
      }
    },
    {
      "kind": "component",
      "id": "ai-consent-banner",
      "capabilities": [],
      "state": [
        {
          "name": "consentState",
          "type": "'granted' | 'required' | 'pending'",
          "description": "Current consent state. Structural only — never the grantee identity.",
          "descriptionKey": "ui.agent.aiConsentBanner.state.consentState"
        },
        {
          "name": "armed",
          "type": "boolean",
          "description": "Whether the consent confirmation checkbox is ticked (required state only).",
          "descriptionKey": "ui.agent.aiConsentBanner.state.armed"
        }
      ],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "ai-consent-banner",
          "description": "Marks the AiConsentBanner root region."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop. Required to address a specific banner from the agent."
        }
      }
    },
    {
      "kind": "component",
      "id": "ai-credits-exhausted-notice",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "ai-credits-exhausted-notice",
          "description": "Marks the out-of-credits notice. Each next-step button carries `data-credits-action=\"buy|upgrade|support|costs\"`."
        }
      }
    },
    {
      "kind": "component",
      "id": "ai-credits-notice",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "ai-credits-notice",
          "description": "Marks the element as a kit AiCreditsNotice card body. Carries a sibling `data-mode=\"included|bundles\"` attribute for which notice is showing."
        }
      }
    },
    {
      "kind": "component",
      "id": "ai-credits-warning",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "ai-credits-warning",
          "description": "Marks the quiet credit lines. Each line carries `data-credits-line=\"low|expiring|exhausted\"`."
        }
      }
    },
    {
      "kind": "component",
      "id": "ai-prompt-input",
      "capabilities": [
        "edit_inline",
        "submit"
      ],
      "state": [
        {
          "name": "value",
          "type": "string",
          "description": "Current text in the composer (no PHI processing).",
          "descriptionKey": "ui.agent.aiPromptInput.state.value"
        },
        {
          "name": "isEmpty",
          "type": "boolean",
          "description": "True when the composer has no text and no attachments.",
          "descriptionKey": "ui.agent.aiPromptInput.state.isEmpty"
        },
        {
          "name": "isSubmitting",
          "type": "boolean",
          "description": "True while an onSubmit invocation is in flight (best-effort).",
          "descriptionKey": "ui.agent.aiPromptInput.state.isSubmitting"
        }
      ],
      "actions": [
        {
          "name": "set_value",
          "safety": "write",
          "argsType": "{ value: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "value": {
                "type": "string"
              }
            },
            "required": [
              "value"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "value": "Summarise the last visit"
              },
              "note": "Replace composer text."
            }
          ],
          "description": "Replace the composer text with the given value.",
          "descriptionKey": "ui.agent.aiPromptInput.actions.setValue"
        },
        {
          "name": "clear",
          "safety": "destructive",
          "idempotent": true,
          "description": "Clear text and attachments. Irreversible from the same UI.",
          "descriptionKey": "ui.agent.aiPromptInput.actions.clear"
        },
        {
          "name": "submit",
          "safety": "write",
          "openWorld": true,
          "description": "Submit the current composer state via onSubmit.",
          "descriptionKey": "ui.agent.aiPromptInput.actions.submit"
        },
        {
          "name": "focus",
          "safety": "read",
          "description": "Move keyboard focus into the textarea.",
          "descriptionKey": "ui.agent.aiPromptInput.actions.focus"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "ai-prompt-input",
          "description": "Marks the AIPromptInput wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop; addresses a specific composer instance."
        }
      }
    },
    {
      "kind": "component",
      "id": "alert",
      "capabilities": [
        "dismiss"
      ],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "alert",
          "description": "Marks the element as a kit Alert. The root also emits `data-state=\"open\" | \"closing\"` while the dismiss animation runs. Alerts inherit native `id` from props, which is what agents address them by. An alert with `dismissKey` that was dismissed in this browser is not rendered at all."
        }
      }
    },
    {
      "kind": "component",
      "id": "anamnesis-card",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "anamnesis-card",
          "description": "Marks the element as a kit AnamnesisCard. The root also emits data-has-flags when at least one answer is a clinical red-flag — a structural boolean only, never the underlying answer."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop — the stable questionnaire identifier."
        }
      }
    },
    {
      "kind": "component",
      "id": "anamnesis-summary-card",
      "capabilities": [],
      "state": [
        {
          "name": "summary",
          "type": "{ id?: string; sectionCount: number; answerCount: number; highlightedCount: number; unansweredCount: number }",
          "description": "Structural summary of the anamnesis card — section, answer, highlighted and unanswered counts plus the consumer id. Never question labels or answer values.",
          "descriptionKey": "ui.agent.anamnesisSummaryCard.state.summary"
        }
      ],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "anamnesis-summary-card",
          "description": "Marks the AnamnesisSummaryCard root region."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        },
        "item": {
          "attr": "data-answer-id",
          "description": "One per answer row (KeyValuePair); the value is the intake field key. Highlighted rows also carry data-highlighted."
        }
      }
    },
    {
      "kind": "component",
      "id": "app-frame",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "app-frame",
          "description": "Marks the AppFrame layout wrapper. Inner landmarks (Header, Sidebar, main) carry their own component hooks."
        }
      }
    },
    {
      "kind": "component",
      "id": "appointment-card",
      "capabilities": [
        "pick"
      ],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "appointment-card",
          "description": "Marks the element as a kit AppointmentCard. The root also emits data-component-id sourced from item.id, data-state with the appointment lifecycle, and data-type with the delivery channel."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "item.id",
          "description": "Sourced from item.id — the stable appointment identifier."
        }
      }
    },
    {
      "kind": "component",
      "id": "appointment-details-panel",
      "capabilities": [
        "open",
        "close",
        "set_value"
      ],
      "state": [
        {
          "name": "eventId",
          "type": "string | null",
          "description": "The occurrence on screen or being read, as the host identifies it. After a failed or refused read, the occurrence it was for when the host says so. Null when there is none, or the host did not say.",
          "descriptionKey": "ui.agent.appointmentDetailsPanel.state.eventId"
        },
        {
          "name": "loadStatus",
          "type": "'loading' | 'ready' | 'error' | 'refused'",
          "description": "Where the read is: loading, ready, failed (with Retry) or refused. Actions need ready.",
          "descriptionKey": "ui.agent.appointmentDetailsPanel.state.loadStatus"
        },
        {
          "name": "appointmentStatus",
          "type": "'confirmed' | 'waiting' | 'in_care' | 'done' | 'cancelled' | 'absent' | null",
          "description": "The appointment status as last saved here or read. Null when none is recorded or nothing is on screen.",
          "descriptionKey": "ui.agent.appointmentDetailsPanel.state.appointmentStatus"
        },
        {
          "name": "allowedStatuses",
          "type": "string[]",
          "description": "The statuses set_status accepts now, in menu order. Empty when the status is read-only.",
          "descriptionKey": "ui.agent.appointmentDetailsPanel.state.allowedStatuses"
        },
        {
          "name": "offeredActions",
          "type": "string[]",
          "description": "The footer actions on offer, as their data-action values (for example edit-appointment, delete-appointment), in footer order, including any folded into More.",
          "descriptionKey": "ui.agent.appointmentDetailsPanel.state.offeredActions"
        },
        {
          "name": "historyOpen",
          "type": "boolean",
          "description": "Whether the History sub-view covers the details.",
          "descriptionKey": "ui.agent.appointmentDetailsPanel.state.historyOpen"
        },
        {
          "name": "privacy",
          "type": "boolean",
          "description": "Whether privacy mode is on. The patient identity and personal fields are then masked on screen.",
          "descriptionKey": "ui.agent.appointmentDetailsPanel.state.privacy"
        }
      ],
      "actions": [
        {
          "name": "open_history",
          "safety": "read",
          "idempotent": true,
          "openWorld": true,
          "errors": [
            "No appointment is on screen, or History is not offered."
          ],
          "description": "Slide the appointment's history over the details, as its header button does; the host reads it then if it did not send it with the details. It lists who changed what, and when.",
          "descriptionKey": "ui.agent.appointmentDetailsPanel.actions.openHistory"
        },
        {
          "name": "close_history",
          "safety": "read",
          "idempotent": true,
          "description": "Return from History to the details.",
          "descriptionKey": "ui.agent.appointmentDetailsPanel.actions.closeHistory"
        },
        {
          "name": "set_status",
          "safety": "phi",
          "argsType": "{ status: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "status": {
                "type": "string",
                "enum": [
                  "confirmed",
                  "waiting",
                  "in_care",
                  "done",
                  "cancelled",
                  "absent"
                ]
              }
            },
            "required": [
              "status"
            ]
          },
          "idempotent": true,
          "openWorld": true,
          "errors": [
            "The status is read-only: no appointment on screen, no host save, readOnly, or no allowed statuses.",
            "The status is not in allowedStatuses.",
            "A status save is already in flight.",
            "The host refused the change. The previous status stays and the panel shows the message."
          ],
          "examples": [
            {
              "args": {
                "status": "waiting"
              }
            }
          ],
          "description": "Save a new appointment status through the host, as the footer control does. Resolves once the host has saved it.",
          "descriptionKey": "ui.agent.appointmentDetailsPanel.actions.setStatus"
        },
        {
          "name": "retry",
          "safety": "read",
          "openWorld": true,
          "errors": [
            "Retry is not offered: the read has not failed or been refused as retryable, or the host offers no Retry."
          ],
          "description": "Ask the host to read the appointment again, after a failed read or a refusal it marked retryable.",
          "descriptionKey": "ui.agent.appointmentDetailsPanel.actions.retry"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "appointment-details-panel",
          "description": "Marks the panel. It also carries data-event-id and data-status. Inside, cards carry data-card (patient, appointment, notes, treatments), footer actions data-action, and the History and description sub-views data-details-subview. An action in offeredActions with no data-action in the footer strip is folded into More: click the panel's [data-component=\"button-group\"] [data-component=\"icon-button\"][aria-haspopup=\"menu\"], and its menu item carries the same data-action."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop, or generated."
        }
      }
    },
    {
      "kind": "component",
      "id": "appointment-peek",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "appointment-peek",
          "description": "Marks the element as a kit AppointmentPeek summary."
        }
      }
    },
    {
      "kind": "component",
      "id": "appointment-timeline",
      "capabilities": [
        "scroll",
        "pick"
      ],
      "state": [
        {
          "name": "items",
          "type": "Array<{ id: string; state: string }>",
          "description": "Currently-rendered appointments. Ids + lifecycle state only — never patient identity.",
          "descriptionKey": "ui.agent.appointmentTimeline.state.items"
        }
      ],
      "actions": [
        {
          "name": "select_item",
          "safety": "read",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              }
            },
            "required": [
              "id"
            ]
          },
          "idempotent": true,
          "description": "Activate the appointment with the given id.",
          "descriptionKey": "ui.agent.appointmentTimeline.actions.selectItem"
        },
        {
          "name": "jump_to_today",
          "safety": "read",
          "idempotent": true,
          "description": "Re-anchor the timeline scroll on today's appointments.",
          "descriptionKey": "ui.agent.appointmentTimeline.actions.jumpToToday"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "appointment-timeline",
          "description": "Marks the AppointmentTimeline wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop. Required to address a specific timeline from the agent."
        },
        "item": {
          "attr": "data-appointment-id",
          "description": "Stable appointment id emitted on each rendered AppointmentCard inside the timeline."
        }
      }
    },
    {
      "kind": "component",
      "id": "appointment-tray",
      "capabilities": [
        "pick"
      ],
      "state": [
        {
          "name": "items",
          "type": "Array<{ id: string; state: string }>",
          "description": "Currently-displayed appointments. Ids + lifecycle state only — never patient identity.",
          "descriptionKey": "ui.agent.appointmentTray.state.items"
        }
      ],
      "actions": [
        {
          "name": "select_item",
          "safety": "read",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              }
            },
            "required": [
              "id"
            ]
          },
          "idempotent": true,
          "description": "Activate the appointment with the given id.",
          "descriptionKey": "ui.agent.appointmentTray.actions.selectItem"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "appointment-tray",
          "description": "Marks the AppointmentTray wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop. Required to address a specific tray from the agent."
        },
        "item": {
          "attr": "data-appointment-id",
          "description": "Stable appointment id emitted on each rendered AppointmentCard inside the tray."
        }
      }
    },
    {
      "kind": "component",
      "id": "aspect-ratio",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "aspect-ratio",
          "description": "Marks the element as a kit AspectRatio wrapper."
        }
      }
    },
    {
      "kind": "component",
      "id": "audio-recorder",
      "capabilities": [
        "capture",
        "submit"
      ],
      "state": [
        {
          "name": "isRecording",
          "type": "boolean",
          "description": "True while actively capturing audio (not paused).",
          "descriptionKey": "ui.agent.audioRecorder.state.isRecording"
        },
        {
          "name": "duration",
          "type": "number",
          "description": "Elapsed recording time in milliseconds (paused time excluded).",
          "descriptionKey": "ui.agent.audioRecorder.state.duration"
        },
        {
          "name": "hasRecording",
          "type": "boolean",
          "description": "True when a completed recording is available for submission.",
          "descriptionKey": "ui.agent.audioRecorder.state.hasRecording"
        }
      ],
      "actions": [
        {
          "name": "start_recording",
          "safety": "write",
          "returns": "void",
          "errors": [
            "Microphone permission denied",
            "No audio input device"
          ],
          "description": "Request microphone permission and begin recording.",
          "descriptionKey": "ui.agent.audioRecorder.actions.startRecording"
        },
        {
          "name": "stop_recording",
          "safety": "write",
          "description": "Stop the current recording and finalise the blob.",
          "descriptionKey": "ui.agent.audioRecorder.actions.stopRecording"
        },
        {
          "name": "discard",
          "safety": "destructive",
          "idempotent": true,
          "description": "Cancel the recording. Irreversible — the captured audio is dropped.",
          "descriptionKey": "ui.agent.audioRecorder.actions.discard"
        },
        {
          "name": "submit",
          "safety": "write",
          "description": "Stop the active recording, finalising it via onRecordingComplete.",
          "descriptionKey": "ui.agent.audioRecorder.actions.submit"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "audio-recorder",
          "description": "Marks the AudioRecorder wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "audio-visualiser",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "audio-visualiser",
          "description": "Marks the element as a kit AudioVisualiser canvas."
        }
      }
    },
    {
      "kind": "component",
      "id": "autocomplete",
      "capabilities": [
        "select_single",
        "filter",
        "open",
        "close"
      ],
      "state": [
        {
          "name": "value",
          "type": "string | null",
          "description": "Currently-selected option value, or null when nothing is committed.",
          "descriptionKey": "ui.agent.autocomplete.state.value"
        },
        {
          "name": "query",
          "type": "string",
          "description": "Current free-text query in the input.",
          "descriptionKey": "ui.agent.autocomplete.state.query"
        },
        {
          "name": "isOpen",
          "type": "boolean",
          "description": "True when the suggestion popup is visible. Open with no suggestions to show reads false.",
          "descriptionKey": "ui.agent.autocomplete.state.isOpen"
        }
      ],
      "actions": [
        {
          "name": "set_value",
          "safety": "write",
          "argsType": "{ value: string | null }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "value": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "value"
            ]
          },
          "idempotent": true,
          "description": "Set the committed value programmatically.",
          "descriptionKey": "ui.agent.autocomplete.actions.setValue"
        },
        {
          "name": "apply_filter",
          "safety": "read",
          "argsType": "{ query: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "query": {
                "type": "string"
              }
            },
            "required": [
              "query"
            ]
          },
          "idempotent": true,
          "description": "Set the input query, which filters the suggestion list.",
          "descriptionKey": "ui.agent.autocomplete.actions.applyFilter"
        },
        {
          "name": "clear",
          "safety": "destructive",
          "idempotent": true,
          "description": "Clear the committed value and the query. Discards the typed input.",
          "descriptionKey": "ui.agent.autocomplete.actions.clear"
        },
        {
          "name": "open",
          "safety": "read",
          "idempotent": true,
          "description": "Open the suggestion list.",
          "descriptionKey": "ui.agent.autocomplete.actions.open"
        },
        {
          "name": "close",
          "safety": "read",
          "idempotent": true,
          "description": "Close the suggestion list.",
          "descriptionKey": "ui.agent.autocomplete.actions.close"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "autocomplete"
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        },
        "item": {
          "attr": "data-option-id",
          "description": "Each suggestion emits its value as data-option-id."
        }
      }
    },
    {
      "kind": "component",
      "id": "avatar",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "avatar",
          "description": "Marks the element as a kit Avatar."
        }
      }
    },
    {
      "kind": "component",
      "id": "badge",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "badge",
          "description": "Marks the element as a kit Badge."
        }
      }
    },
    {
      "kind": "component",
      "id": "benefit-card",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "benefit-card",
          "description": "Marks the BenefitCard root. Presentational — no agent-driven state."
        }
      }
    },
    {
      "kind": "component",
      "id": "bishop-score",
      "capabilities": [
        "set_value"
      ],
      "state": [
        {
          "name": "selection",
          "type": "Partial<Record<BishopComponent, string>>",
          "description": "The five cervical-exam findings keyed by component (dilation, effacement, station, consistency, position). Each value is an enumerated option key, not free text.",
          "descriptionKey": "ui.agent.bishopScore.state.selection"
        },
        {
          "name": "result",
          "type": "{ total: number, band: string } | null",
          "description": "Computed Bishop result — total (0–13) and favourability band (unfavourable / intermediate / favourable). Null until all five findings are set.",
          "descriptionKey": "ui.agent.bishopScore.state.result"
        }
      ],
      "actions": [
        {
          "name": "set_value",
          "safety": "write",
          "argsType": "{ component: BishopComponent, value: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "component": {
                "enum": [
                  "dilation",
                  "effacement",
                  "station",
                  "consistency",
                  "position"
                ],
                "description": "Which cervical-exam finding to set."
              },
              "value": {
                "type": "string",
                "description": "Enumerated option key for that finding (e.g. dilation \"closed\" | \"1-2\" | \"3-4\" | \"5+\")."
              }
            },
            "required": [
              "component",
              "value"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "component": "dilation",
                "value": "3-4"
              },
              "note": "Record cervical dilation of 3–4 cm (2 points)."
            }
          ],
          "description": "Set one cervical-exam finding to an enumerated option value. Unknown component/value pairs are ignored.",
          "descriptionKey": "ui.agent.bishopScore.actions.setValue"
        },
        {
          "name": "reset",
          "safety": "write",
          "idempotent": true,
          "description": "Clear all five findings and the computed result.",
          "descriptionKey": "ui.agent.bishopScore.actions.reset"
        },
        {
          "name": "get_result",
          "safety": "read",
          "returns": "{ total: number, band: string } | null",
          "returnsSchema": {
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "total": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 13
                  },
                  "band": {
                    "enum": [
                      "unfavourable",
                      "intermediate",
                      "favourable"
                    ]
                  }
                },
                "required": [
                  "total",
                  "band"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "idempotent": true,
          "description": "Return the computed Bishop result, or null until all five findings are set.",
          "descriptionKey": "ui.agent.bishopScore.actions.getResult"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "bishop-score",
          "description": "Marks the BishopScore calculator wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop. Required to address a specific calculator instance."
        }
      }
    },
    {
      "kind": "component",
      "id": "bmi-calculator",
      "capabilities": [
        "set_value",
        "view_change"
      ],
      "state": [
        {
          "name": "unitSystem",
          "type": "'metric' | 'imperial'",
          "description": "Active unit system the inputs are entered in.",
          "descriptionKey": "ui.agent.bmiCalculator.state.unitSystem"
        },
        {
          "name": "inputs",
          "type": "{ heightCm: number | null, weightKg: number | null }",
          "description": "Canonical metric measurements regardless of the active unit system — height in centimetres and weight in kilograms, or null when unset.",
          "descriptionKey": "ui.agent.bmiCalculator.state.inputs"
        },
        {
          "name": "result",
          "type": "{ bmi: number, category: string } | null",
          "description": "Computed BMI (kg/m²) and WHO category (underweight / normal / overweight / obese). Null until both height and weight are valid.",
          "descriptionKey": "ui.agent.bmiCalculator.state.result"
        }
      ],
      "actions": [
        {
          "name": "set_value",
          "safety": "write",
          "argsType": "{ heightCm?: number | null, weightKg?: number | null }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "heightCm": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "Height in centimetres (canonical metric).",
                "minimum": 0
              },
              "weightKg": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "Weight in kilograms (canonical metric).",
                "minimum": 0
              }
            },
            "additionalProperties": false
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "heightCm": 175,
                "weightKg": 72
              },
              "note": "A 175 cm, 72 kg patient → BMI ~23.5 (normal)."
            }
          ],
          "description": "Set height (cm) and/or weight (kg) in canonical metric units. Omitted fields are left unchanged.",
          "descriptionKey": "ui.agent.bmiCalculator.actions.setValue"
        },
        {
          "name": "set_unit_system",
          "safety": "write",
          "argsType": "{ unitSystem: 'metric' | 'imperial' }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "unitSystem": {
                "enum": [
                  "metric",
                  "imperial"
                ],
                "description": "Unit system to display the inputs in."
              }
            },
            "required": [
              "unitSystem"
            ]
          },
          "idempotent": true,
          "description": "Switch the input unit system. Entered figures are preserved by conversion; the computed BMI is unchanged.",
          "descriptionKey": "ui.agent.bmiCalculator.actions.setUnitSystem"
        },
        {
          "name": "reset",
          "safety": "write",
          "idempotent": true,
          "description": "Clear height and weight and the computed result.",
          "descriptionKey": "ui.agent.bmiCalculator.actions.reset"
        },
        {
          "name": "get_result",
          "safety": "read",
          "returns": "{ bmi: number, category: string } | null",
          "returnsSchema": {
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "bmi": {
                    "type": "number",
                    "minimum": 0
                  },
                  "category": {
                    "enum": [
                      "underweight",
                      "normal",
                      "overweight",
                      "obese"
                    ]
                  }
                },
                "required": [
                  "bmi",
                  "category"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "idempotent": true,
          "description": "Return the computed BMI + WHO category, or null until both inputs are valid.",
          "descriptionKey": "ui.agent.bmiCalculator.actions.getResult"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "bmi-calculator",
          "description": "Marks the BmiCalculator wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop. Required to address a specific calculator instance."
        }
      }
    },
    {
      "kind": "component",
      "id": "booking",
      "capabilities": [
        "navigate"
      ],
      "state": [
        {
          "name": "variant",
          "type": "string",
          "description": "Active variant — one of `inline-list`, `accordion`, `calendar`, `flexible`, `progress`.",
          "descriptionKey": "ui.agent.booking.state.variant"
        },
        {
          "name": "currentStep",
          "type": "number",
          "description": "The step the flow is on: 1 insurance, 2 specialty, 3 service, 4 provider, 5 date, 6 time, 7 patient details, payment or optional SMS code verification, 8 confirmation after all required steps succeed, including the \"Time reserved\" view that opens a host address after a short delay. Read this back after `goto_step` to see where the clamp landed.",
          "descriptionKey": "ui.agent.booking.state.currentStep"
        }
      ],
      "actions": [
        {
          "name": "reset",
          "safety": "destructive",
          "idempotent": true,
          "errors": [
            "Refused while a payment session is open (step 7): the consumer must cancel the hold first.",
            "Refused while SMS code verification is pending (step 7): the locked form and code box stay, and the submitted booking remains active. The host owns cancellation."
          ],
          "description": "Clear the booking value back to an empty state. Use to abandon an in-progress flow.",
          "descriptionKey": "ui.agent.booking.actions.reset"
        },
        {
          "name": "goto_step",
          "safety": "read",
          "argsType": "{ step: 1 | 2 | 3 | 4 | 5 | 6 | 7 }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "step": {
                "type": "integer",
                "enum": [
                  1,
                  2,
                  3,
                  4,
                  5,
                  6,
                  7
                ],
                "description": "Target step (1-7)."
              }
            },
            "required": [
              "step"
            ]
          },
          "idempotent": true,
          "errors": [
            "Navigation stays on step 7 while payment or SMS code verification is pending.",
            "Requested step is not yet reachable — clamped to the first incomplete step.",
            "Requested step is hidden for this practice (e.g. insurance outside Germany, or provider choice turned off) — clamped to the first incomplete step."
          ],
          "examples": [
            {
              "args": {
                "step": 1
              },
              "note": "Return to the first step."
            }
          ],
          "description": "Jump to the given step. A step that is hidden for this practice, or that sits ahead of the first incomplete step, clamps to that first incomplete step — read `currentStep` back to see where it landed.",
          "descriptionKey": "ui.agent.booking.actions.gotoStep"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "booking",
          "description": "Marks the Booking root region. The host prop hideEmail (boolean, default false) hides the email field, skips its validation and omits email from submission. The host prop emailOptional (boolean, default false) keeps email visible and optional unless used for confirmation. Email is marked and validated as required when selected in the channel picker or singleConfirmationChannel radio, or when the effective confirmation channel is email. With a hidden picker, the form and success screen use the sole enabled channel, or email when multiple channels are enabled. This includes payment and blocked-payment flows, which omit stored selections from submission. Omitting confirmationChannels also defaults to email. Selecting SMS without email makes the field optional again. The optional/required marker updates visually when the channel changes, with no announcement of that change. Validation updates immediately using the existing email error. With emailOptional, surrounding spaces are trimmed before validation, even when email is required for confirmation. Optional blank values are omitted from submission; filled values are sent trimmed. hideEmail takes precedence over emailOptional. Neither prop changes confirmation channels; pair with confirmationChannels [\"sms\"] for SMS-only confirmation with no channel picker. The optional codeStep prop adds SMS verification after submission and before any payment: the submitted form stays in place but locked (controls disabled, text still readable, not hidden), the code box opens below it, and a Change button, for the patient only (no agent action unlocks it), unlocks the form for a new booking request (the host keeps the earlier request until it expires; the kit cannot cancel it). With payment, a correct code opens the payment stage, and the step remains 7 until payment succeeds; without payment it remains 7 until verification succeeds. It then becomes 8. Patient contact details and verification codes are never exposed through this adapter."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "booking-reserved",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "booking-reserved",
          "description": "Marks the standalone or embedded reserved-time handover. The host verifies the booking and supplies the destination. No URL, appointment details or patient data are exposed through the adapter."
        }
      }
    },
    {
      "kind": "component",
      "id": "breadcrumb",
      "capabilities": [
        "navigate"
      ],
      "state": [
        {
          "name": "items",
          "type": "Array<{ id: string, href?: string }>",
          "description": "Ordered list of crumb ids + hrefs in display order. Labels are intentionally excluded — they may contain PHI.",
          "descriptionKey": "ui.agent.breadcrumb.state.items"
        }
      ],
      "actions": [
        {
          "name": "navigate_to",
          "safety": "read",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "Stable opaque crumb id (from getItems)."
              }
            },
            "required": [
              "id"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "id": "/patients"
              },
              "note": "Navigate to the patients crumb."
            }
          ],
          "description": "Activate the crumb with the given id — equivalent to clicking the link.",
          "descriptionKey": "ui.agent.breadcrumb.actions.navigateTo"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "breadcrumb",
          "description": "Marks the Breadcrumb root `<nav>`."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        },
        "item": {
          "attr": "data-crumb-id",
          "description": "Stable opaque id of a crumb. Labels are NEVER carried in data-* — they may contain PHI."
        }
      }
    },
    {
      "kind": "component",
      "id": "button",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "button",
          "description": "Marks the element as a kit Button. Safety is declared by the host pattern, not the button. Buttons inherit native `id` from props, which is what agents address them by."
        }
      }
    },
    {
      "kind": "component",
      "id": "button-group",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "button-group",
          "description": "Marks the ButtonGroup wrapper."
        },
        "item": {
          "attr": "data-action",
          "description": "Each child's own hook, set by the host. It is on the live control in the strip, or on its More menu item while that menu is open; the hidden measuring copies drop it. Target a control by `data-action`, not by `id`: a child folded into More keeps no `id`."
        }
      }
    },
    {
      "kind": "component",
      "id": "calculator-dialog",
      "capabilities": [
        "open",
        "close",
        "dismiss"
      ],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "calculator-dialog",
          "description": "Marks the modal body wrapper that hosts the calculator content. The surrounding Dialog (with its own data-component=\"dialog\") owns the open-state handle."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop. Emitted on this body wrapper AND forwarded to the composed Dialog content, which registers `dialogAgent` under the same id — so one id addresses both the modal body and the open-state handle."
        }
      }
    },
    {
      "kind": "component",
      "id": "calendar",
      "capabilities": [
        "view_change",
        "range_navigate",
        "pick"
      ],
      "state": [
        {
          "name": "currentView",
          "type": "CalendarView",
          "description": "Active view name (e.g. dayGridMonth, timeGridWeek).",
          "descriptionKey": "ui.agent.calendar.state.currentView"
        },
        {
          "name": "currentDate",
          "type": "iso-date",
          "description": "ISO date anchor of the visible range.",
          "descriptionKey": "ui.agent.calendar.state.currentDate"
        },
        {
          "name": "currentTitle",
          "type": "string",
          "description": "Human title of the current range (e.g. \"April 2026\").",
          "descriptionKey": "ui.agent.calendar.state.currentTitle"
        }
      ],
      "actions": [
        {
          "name": "today",
          "safety": "read",
          "idempotent": true,
          "description": "Jump to the current day.",
          "descriptionKey": "ui.agent.calendar.actions.today"
        },
        {
          "name": "prev",
          "safety": "read",
          "description": "Move to the previous range.",
          "descriptionKey": "ui.agent.calendar.actions.prev"
        },
        {
          "name": "next",
          "safety": "read",
          "description": "Move to the next range.",
          "descriptionKey": "ui.agent.calendar.actions.next"
        },
        {
          "name": "goto_date",
          "safety": "read",
          "argsType": "{ date: string | Date }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "date": {
                "type": "string",
                "format": "date",
                "description": "Target date — ISO 8601 string (or Date at runtime)."
              }
            },
            "required": [
              "date"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "date": "2026-04-15"
              },
              "note": "Jump to 15 April 2026."
            }
          ],
          "description": "Navigate to a specific date.",
          "descriptionKey": "ui.agent.calendar.actions.gotoDate"
        },
        {
          "name": "change_view",
          "safety": "read",
          "argsType": "{ view: CalendarView }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "view": {
                "type": "string",
                "enum": [
                  "dayGridMonth",
                  "timeGridWeek",
                  "timeGridDay",
                  "listWeek",
                  "resourceTimeGridDayChair",
                  "resourceTimeGridThreeDaysChair",
                  "resourceTimeGridWeekChair",
                  "resourceTimeGridDayOperator",
                  "resourceTimeGridThreeDaysOperator",
                  "resourceTimeGridWeekOperator"
                ],
                "description": "Target view name."
              }
            },
            "required": [
              "view"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "view": "timeGridWeek"
              },
              "note": "Switch to the week view."
            }
          ],
          "description": "Switch the calendar to the given view.",
          "descriptionKey": "ui.agent.calendar.actions.changeView"
        },
        {
          "name": "focus_event",
          "safety": "read",
          "argsType": "{ eventId: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "eventId": {
                "type": "string",
                "description": "Stable event id (matches a data-event-id node)."
              }
            },
            "required": [
              "eventId"
            ]
          },
          "errors": [
            "No DOM node matches the given event id — no-op."
          ],
          "description": "Scroll an event into view and briefly highlight it.",
          "descriptionKey": "ui.agent.calendar.actions.focusEvent"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "calendar",
          "description": "Marks the Calendar wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        },
        "item": {
          "attr": "data-event-id",
          "description": "Emitted on every rendered FullCalendar event by the kit event renderer. Used by focusEvent. Cards also carry data-kind=\"task\"|\"draft\"|\"pending-details\"|\"appointment\" and data-status for classification."
        }
      }
    },
    {
      "kind": "component",
      "id": "card",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "card",
          "description": "Marks the Card root. Interactive Cards inherit `role=\"button\"` (unless `asChild` is used) and are addressed by their native `id`."
        }
      }
    },
    {
      "kind": "component",
      "id": "care-plan-card",
      "capabilities": [
        "expand"
      ],
      "state": [
        {
          "name": "state",
          "type": "'estimate' | 'accepted' | 'discarded' | 'closed'",
          "description": "The plan lifecycle state. Enum value only — never the localised label or any PHI.",
          "descriptionKey": "ui.agent.carePlanCard.state.state"
        },
        {
          "name": "progress",
          "type": "{ done: number; total: number }",
          "description": "Line progress as done / total counts. Counts only — never treatment names or operator identity.",
          "descriptionKey": "ui.agent.carePlanCard.state.progress"
        }
      ],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "care-plan-card",
          "description": "Marks the CarePlanCard root region."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop. Addresses a specific plan."
        }
      }
    },
    {
      "kind": "component",
      "id": "care-plan-entry-card",
      "capabilities": [
        "expand"
      ],
      "state": [
        {
          "name": "done",
          "type": "boolean",
          "description": "Whether the treatment line is marked executed.",
          "descriptionKey": "ui.agent.carePlanEntryCard.state.done"
        },
        {
          "name": "phaseProgress",
          "type": "{ executed: number; total: number }",
          "description": "Phase progress as executed / total counts. Counts only — never phase labels or operator identity.",
          "descriptionKey": "ui.agent.carePlanEntryCard.state.phaseProgress"
        }
      ],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "care-plan-entry-card",
          "description": "Marks the CarePlanEntryCard root region."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop. Addresses a specific line."
        }
      }
    },
    {
      "kind": "component",
      "id": "care-plan-header",
      "capabilities": [],
      "state": [
        {
          "name": "state",
          "type": "'estimate' | 'accepted' | 'discarded' | 'closed'",
          "description": "The plan lifecycle state. Enum value only — never the localised label or any PHI.",
          "descriptionKey": "ui.agent.carePlanHeader.state.state"
        },
        {
          "name": "alertCount",
          "type": "number",
          "description": "How many attention alerts (e.g. missing signature) are showing. Count only — never the alert labels.",
          "descriptionKey": "ui.agent.carePlanHeader.state.alertCount"
        }
      ],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "care-plan-header",
          "description": "Marks the CarePlanHeader root region."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop. Addresses a specific plan header."
        }
      }
    },
    {
      "kind": "component",
      "id": "carousel",
      "capabilities": [
        "scroll"
      ],
      "state": [
        {
          "name": "activeIndex",
          "type": "number",
          "description": "Zero-based index of the currently snapped slide.",
          "descriptionKey": "ui.agent.carousel.state.activeIndex"
        },
        {
          "name": "count",
          "type": "number",
          "description": "Total slide count.",
          "descriptionKey": "ui.agent.carousel.state.count"
        }
      ],
      "actions": [
        {
          "name": "scroll_to",
          "safety": "read",
          "argsType": "{ index: number }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "index": {
                "type": "integer",
                "minimum": 0,
                "description": "Zero-based index of the slide to snap to."
              }
            },
            "required": [
              "index"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "index": 0
              },
              "note": "Snap back to the first slide."
            }
          ],
          "description": "Scroll to the slide at the given index.",
          "descriptionKey": "ui.agent.carousel.actions.scrollTo"
        },
        {
          "name": "scroll_prev",
          "safety": "read",
          "description": "Scroll to the previous slide.",
          "descriptionKey": "ui.agent.carousel.actions.scrollPrev"
        },
        {
          "name": "scroll_next",
          "safety": "read",
          "description": "Scroll to the next slide.",
          "descriptionKey": "ui.agent.carousel.actions.scrollNext"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "carousel"
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop on Carousel."
        },
        "item": {
          "attr": "data-slide-id",
          "description": "Each Carousel.Item emits its `id` prop as `data-slide-id`. `data-slide-index` carries the zero-based position alongside."
        }
      }
    },
    {
      "kind": "component",
      "id": "chart",
      "capabilities": [
        "view_change"
      ],
      "state": [
        {
          "name": "declaredType",
          "type": "'line' | 'bar' | 'pie' | 'donut' | 'area' | 'radialBar'",
          "description": "The consumer-declared chart type — the shape `update_series` expects.",
          "descriptionKey": "ui.agent.chart.state.declaredType"
        },
        {
          "name": "effectiveType",
          "type": "'line' | 'bar' | 'pie' | 'donut' | 'area' | 'radialBar'",
          "description": "The type currently rendered — differs from declaredType after a type-switcher pick.",
          "descriptionKey": "ui.agent.chart.state.effectiveType"
        },
        {
          "name": "availableTypes",
          "type": "ChartType[]",
          "description": "Types the switcher offers. Empty when the chart has no type switcher.",
          "descriptionKey": "ui.agent.chart.state.availableTypes"
        }
      ],
      "actions": [
        {
          "name": "change_view",
          "safety": "write",
          "argsType": "type",
          "argsSchema": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "line",
                  "bar",
                  "area",
                  "pie",
                  "donut"
                ],
                "description": "The chart type to render."
              }
            },
            "required": [
              "type"
            ]
          },
          "returns": "boolean (accepted)",
          "returnsSchema": {
            "type": "boolean",
            "description": "True when the switch was applied; false when the chart has no type switcher or the type is not offered (check availableTypes first)."
          },
          "idempotent": true,
          "description": "Switch the rendered chart type via the type switcher. No-op (returns false) when the chart has no switcher or the type is not offered.",
          "descriptionKey": "ui.agent.chart.actions.changeView"
        },
        {
          "name": "update_series",
          "safety": "write",
          "argsType": "series",
          "argsSchema": {
            "type": "object",
            "properties": {
              "series": {
                "oneOf": [
                  {
                    "type": "array",
                    "description": "Categorical series for line / bar / area charts.",
                    "items": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "data": {
                          "type": "array",
                          "items": {
                            "type": "number"
                          }
                        },
                        "role": {
                          "type": "string",
                          "enum": [
                            "primary",
                            "compare"
                          ],
                          "description": "Optional. 'compare' renders this series as a secondary, colour-blind-safe overlay (e.g. the previous period) — a dotted stroke in its paired primary's colour for line/area, a tinted bar with a dotted outline for bar. Omit for a normal primary series."
                        },
                        "axis": {
                          "type": "string",
                          "enum": [
                            "primary",
                            "secondary"
                          ],
                          "description": "Optional. 'secondary' plots this series on the chart's second value scale; it needs the host to configure secondaryAxis. Omit for the primary scale."
                        }
                      },
                      "required": [
                        "name",
                        "data"
                      ]
                    }
                  },
                  {
                    "type": "array",
                    "description": "Flat values for pie / donut / radialBar charts.",
                    "items": {
                      "type": "number"
                    }
                  }
                ]
              }
            },
            "required": [
              "series"
            ]
          },
          "idempotent": true,
          "description": "Replace the chart series without remounting. Pass the DECLARED type’s shape (see declaredType state); when the user has switched the view cross-shape the values are converted to the rendered shape. The data and its summary table persist across type switches, resizes and theme changes until the host passes a new series prop.",
          "descriptionKey": "ui.agent.chart.actions.updateSeries"
        },
        {
          "name": "export_png",
          "safety": "read",
          "returns": "string (PNG data URI)",
          "returnsSchema": {
            "type": "string",
            "description": "A `data:image/png;base64,…` URI of the rendered chart."
          },
          "idempotent": true,
          "description": "Return a PNG data URI of the chart for export or screenshotting. Waits until series pushed with update_series are drawn.",
          "descriptionKey": "ui.agent.chart.actions.exportPng"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "chart"
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "chat-container",
      "capabilities": [
        "scroll"
      ],
      "state": [
        {
          "name": "isAtBottom",
          "type": "boolean",
          "description": "True when the viewport is pinned to the newest message. The read-back for `scroll_to_bottom` — the direct confirmation that the latest turn is on screen.",
          "descriptionKey": "ui.agent.chatContainer.state.isAtBottom"
        },
        {
          "name": "messageCount",
          "type": "number",
          "description": "Number of messages currently rendered in the log. Count only — never message content.",
          "descriptionKey": "ui.agent.chatContainer.state.messageCount"
        }
      ],
      "actions": [
        {
          "name": "scroll_to_bottom",
          "safety": "read",
          "argsType": "{ smooth?: boolean }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "smooth": {
                "type": "boolean",
                "description": "Animate the scroll when true (default). Forced off under reduced motion."
              }
            }
          },
          "idempotent": true,
          "description": "Scroll the conversation viewport to the latest message. Read the `isAtBottom` slot afterwards to confirm the viewport settled there.",
          "descriptionKey": "ui.agent.chatContainer.actions.scrollToBottom"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "chat-container"
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "chat-input",
      "capabilities": [
        "edit_inline",
        "submit"
      ],
      "state": [
        {
          "name": "value",
          "type": "string",
          "description": "Current text in the composer.",
          "descriptionKey": "ui.agent.chatInput.state.value"
        },
        {
          "name": "isEmpty",
          "type": "boolean",
          "description": "True when the composer has no text.",
          "descriptionKey": "ui.agent.chatInput.state.isEmpty"
        }
      ],
      "actions": [
        {
          "name": "set_value",
          "safety": "write",
          "argsType": "{ value: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "value": {
                "type": "string",
                "description": "New composer text, replacing the current value."
              }
            },
            "required": [
              "value"
            ]
          },
          "idempotent": true,
          "description": "Replace the composer text.",
          "descriptionKey": "ui.agent.chatInput.actions.setValue"
        },
        {
          "name": "clear",
          "safety": "destructive",
          "idempotent": true,
          "description": "Clear the composer. Irreversible from the same UI.",
          "descriptionKey": "ui.agent.chatInput.actions.clear"
        },
        {
          "name": "submit",
          "safety": "write",
          "openWorld": true,
          "description": "Submit the current composer state via onSubmit.",
          "descriptionKey": "ui.agent.chatInput.actions.submit"
        },
        {
          "name": "focus",
          "safety": "read",
          "description": "Move keyboard focus into the textarea.",
          "descriptionKey": "ui.agent.chatInput.actions.focus"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "chat-input",
          "description": "Marks the ChatInput wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "chat-message",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "chat-message",
          "description": "Marks the ChatMessage article element. Agents address an individual message by its native `id` and read role / status from the `data-role` and `data-status` attributes emitted on this element (`data-status` is omitted when the message has no status)."
        }
      }
    },
    {
      "kind": "component",
      "id": "checkbox",
      "capabilities": [
        "set_value"
      ],
      "state": [
        {
          "name": "checked",
          "type": "boolean | \"indeterminate\"",
          "description": "Current checked state.",
          "descriptionKey": "ui.agent.checkbox.state.checked"
        }
      ],
      "actions": [
        {
          "name": "set_checked",
          "safety": "write",
          "argsType": "{ checked: boolean | \"indeterminate\" }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "checked": {
                "oneOf": [
                  {
                    "type": "boolean"
                  },
                  {
                    "const": "indeterminate"
                  }
                ],
                "description": "Target state: true, false, or the tri-state \"indeterminate\"."
              }
            },
            "required": [
              "checked"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "checked": true
              },
              "note": "Tick the box."
            }
          ],
          "description": "Set the checked state to a specific value.",
          "descriptionKey": "ui.agent.checkbox.actions.setChecked"
        },
        {
          "name": "toggle",
          "safety": "write",
          "description": "Flip the checked state between checked and unchecked.",
          "descriptionKey": "ui.agent.checkbox.actions.toggle"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "checkbox",
          "description": "Marks the Checkbox wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "checkbox-group",
      "capabilities": [
        "select_multiple"
      ],
      "state": [
        {
          "name": "selection",
          "type": "string[]",
          "description": "Values of currently-checked options.",
          "descriptionKey": "ui.agent.checkboxGroup.state.selection"
        }
      ],
      "actions": [
        {
          "name": "set_selection",
          "safety": "write",
          "argsType": "{ ids: string[] }",
          "description": "Replace the current selection with the given option values.",
          "descriptionKey": "ui.agent.checkboxGroup.actions.setSelection"
        },
        {
          "name": "clear_selection",
          "safety": "destructive",
          "description": "Uncheck every option in the group.",
          "descriptionKey": "ui.agent.checkboxGroup.actions.clearSelection"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "checkbox-group",
          "description": "Marks the CheckboxGroup fieldset."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        },
        "item": {
          "attr": "data-option-id",
          "description": "Stable opaque value emitted on each rendered Checkbox child within the group."
        }
      }
    },
    {
      "kind": "component",
      "id": "city-input",
      "capabilities": [
        "set_value"
      ],
      "state": [
        {
          "name": "value",
          "type": "string",
          "description": "Current city / town value.",
          "descriptionKey": "ui.agent.cityInput.state.value"
        },
        {
          "name": "isEmpty",
          "type": "boolean",
          "description": "Whether the field has no value.",
          "descriptionKey": "ui.agent.cityInput.state.isEmpty"
        }
      ],
      "actions": [
        {
          "name": "set_value",
          "safety": "write",
          "argsType": "{ value: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "value": {
                "type": "string"
              }
            },
            "required": [
              "value"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "value": "Milano"
              },
              "note": "Set the city to Milano."
            }
          ],
          "description": "Replace the city value.",
          "descriptionKey": "ui.agent.cityInput.actions.setValue"
        },
        {
          "name": "clear",
          "safety": "destructive",
          "idempotent": true,
          "description": "Empty the field. Loses any typed value.",
          "descriptionKey": "ui.agent.cityInput.actions.clear"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "city-input"
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "clinical-note-card",
      "capabilities": [],
      "state": [
        {
          "name": "noteId",
          "type": "string | undefined",
          "description": "Stable identifier of the rendered note, when supplied.",
          "descriptionKey": "ui.agent.clinicalNoteCard.state.noteId"
        },
        {
          "name": "pinned",
          "type": "boolean",
          "description": "Whether the note is pinned to the top of the timeline.",
          "descriptionKey": "ui.agent.clinicalNoteCard.state.pinned"
        },
        {
          "name": "flagged",
          "type": "boolean",
          "description": "Whether the note is flagged for follow-up.",
          "descriptionKey": "ui.agent.clinicalNoteCard.state.flagged"
        },
        {
          "name": "attachmentKind",
          "type": "'patient' | 'carePlan' | 'carePlanEntry' | 'phase' | 'xray' | undefined",
          "description": "Structural kind the note is attached to. Never the attachment identity or content.",
          "descriptionKey": "ui.agent.clinicalNoteCard.state.attachmentKind"
        }
      ],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "clinical-note-card",
          "description": "Marks the ClinicalNoteCard root. Also emits data-pinned / data-flagged / data-attached-to structural hooks; the pin / flag toggles carry data-note-action=\"pin\" | \"flag\"."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop — addresses a specific note."
        }
      }
    },
    {
      "kind": "component",
      "id": "collapsible",
      "capabilities": [
        "expand"
      ],
      "state": [
        {
          "name": "isOpen",
          "type": "boolean",
          "description": "True when the content panel is expanded.",
          "descriptionKey": "ui.agent.collapsible.state.isOpen"
        }
      ],
      "actions": [
        {
          "name": "toggle",
          "safety": "read",
          "description": "Toggle between open and closed.",
          "descriptionKey": "ui.agent.collapsible.actions.toggle"
        },
        {
          "name": "open",
          "safety": "read",
          "idempotent": true,
          "description": "Expand the content panel.",
          "descriptionKey": "ui.agent.collapsible.actions.open"
        },
        {
          "name": "close",
          "safety": "read",
          "idempotent": true,
          "description": "Collapse the content panel.",
          "descriptionKey": "ui.agent.collapsible.actions.close"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "collapsible",
          "description": "Marks the Collapsible root."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "color-picker",
      "capabilities": [
        "set_value"
      ],
      "state": [
        {
          "name": "value",
          "type": "string",
          "description": "Currently picked colour as a hex string (e.g. \"#3b82f6\").",
          "descriptionKey": "ui.agent.colorPicker.state.value"
        }
      ],
      "actions": [
        {
          "name": "set_value",
          "safety": "write",
          "argsType": "{ hex: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "hex": {
                "type": "string",
                "description": "Hex colour string, e.g. \"#3b82f6\"."
              }
            },
            "required": [
              "hex"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "hex": "#3b82f6"
              },
              "note": "Set to brand blue."
            }
          ],
          "description": "Set the picked colour from a hex string.",
          "descriptionKey": "ui.agent.colorPicker.actions.setValue"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "color-picker",
          "description": "Marks the ColorPicker wrapper (inline) or trigger (popover variant)."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "combobox",
      "capabilities": [
        "select_single",
        "set_value",
        "filter",
        "open",
        "close"
      ],
      "state": [
        {
          "name": "value",
          "type": "string | null",
          "description": "Currently-selected option value, or null when nothing is selected.",
          "descriptionKey": "ui.agent.combobox.state.value"
        },
        {
          "name": "query",
          "type": "string",
          "description": "Current filter query in the combobox input.",
          "descriptionKey": "ui.agent.combobox.state.query"
        },
        {
          "name": "isOpen",
          "type": "boolean",
          "description": "True when the option list is visible.",
          "descriptionKey": "ui.agent.combobox.state.isOpen"
        }
      ],
      "actions": [
        {
          "name": "set_value",
          "safety": "write",
          "argsType": "{ value: string | null }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "value": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Option value to select, or null to clear."
              }
            },
            "required": [
              "value"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "value": "it"
              },
              "note": "Select the \"it\" option."
            }
          ],
          "description": "Set the selected value programmatically.",
          "descriptionKey": "ui.agent.combobox.actions.setValue"
        },
        {
          "name": "apply_filter",
          "safety": "read",
          "argsType": "{ query: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "query": {
                "type": "string",
                "description": "Filter text for the list."
              }
            },
            "required": [
              "query"
            ]
          },
          "idempotent": true,
          "description": "Set the filter query for the option list.",
          "descriptionKey": "ui.agent.combobox.actions.applyFilter"
        },
        {
          "name": "clear_selection",
          "safety": "destructive",
          "idempotent": true,
          "description": "Clear the current selection.",
          "descriptionKey": "ui.agent.combobox.actions.clearSelection"
        },
        {
          "name": "open",
          "safety": "read",
          "idempotent": true,
          "description": "Open the option list.",
          "descriptionKey": "ui.agent.combobox.actions.open"
        },
        {
          "name": "close",
          "safety": "read",
          "idempotent": true,
          "description": "Close the option list.",
          "descriptionKey": "ui.agent.combobox.actions.close"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "combobox"
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        },
        "item": {
          "attr": "data-option-id",
          "description": "Each option emits its value as data-option-id."
        }
      }
    },
    {
      "kind": "component",
      "id": "command-palette",
      "capabilities": [
        "open",
        "close",
        "filter"
      ],
      "state": [
        {
          "name": "query",
          "type": "string",
          "description": "Current filter query in the command palette input.",
          "descriptionKey": "ui.agent.commandPalette.state.query"
        },
        {
          "name": "isOpen",
          "type": "boolean",
          "description": "True when the palette is visible.",
          "descriptionKey": "ui.agent.commandPalette.state.isOpen"
        }
      ],
      "actions": [
        {
          "name": "open",
          "safety": "read",
          "idempotent": true,
          "description": "Open the command palette.",
          "descriptionKey": "ui.agent.commandPalette.actions.open"
        },
        {
          "name": "close",
          "safety": "read",
          "idempotent": true,
          "description": "Close the command palette.",
          "descriptionKey": "ui.agent.commandPalette.actions.close"
        },
        {
          "name": "apply_filter",
          "safety": "read",
          "argsType": "{ query: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "query": {
                "type": "string",
                "description": "Filter text matched against command labels."
              }
            },
            "required": [
              "query"
            ]
          },
          "idempotent": true,
          "description": "Set the filter query.",
          "descriptionKey": "ui.agent.commandPalette.actions.applyFilter"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "command-palette"
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        },
        "item": {
          "attr": "data-command-id",
          "description": "Each command item emits its key as data-command-id."
        }
      }
    },
    {
      "kind": "component",
      "id": "connection-status",
      "capabilities": [
        "submit",
        "dismiss"
      ],
      "state": [
        {
          "name": "status",
          "type": "string",
          "description": "Connection state of the external service: 'connected', 'disconnected', 'pending', or 'error'.",
          "descriptionKey": "ui.agent.connectionStatus.state.status"
        }
      ],
      "actions": [
        {
          "name": "connect",
          "safety": "write",
          "openWorld": true,
          "description": "Begin connecting the external service — invokes the consumer-supplied onConnect handler.",
          "descriptionKey": "ui.agent.connectionStatus.actions.connect"
        },
        {
          "name": "disconnect",
          "safety": "destructive",
          "openWorld": true,
          "description": "Disconnect the external service — invokes the consumer-supplied onDisconnect handler.",
          "descriptionKey": "ui.agent.connectionStatus.actions.disconnect"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "connection-status",
          "description": "Marks the ConnectionStatus wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "contact-card",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "contact-card",
          "description": "Marks the outer Card wrapper of a ContactCard."
        }
      }
    },
    {
      "kind": "component",
      "id": "contact-profile-card",
      "capabilities": [],
      "state": [
        {
          "name": "profession",
          "type": "string",
          "description": "Profession string the card is currently rendering — undefined when the consumer omitted it.",
          "descriptionKey": "ui.agent.contactProfileCard.state.profession"
        }
      ],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "contact-profile-card",
          "description": "Marks the ContactProfileCard root region."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "control-room-rail",
      "capabilities": [
        "open",
        "close",
        "select_single"
      ],
      "state": [
        {
          "name": "activeToolId",
          "type": "string | null",
          "description": "Id of the tool whose panel is currently open, or null when the rail is collapsed to its strip. No panel content is ever exposed.",
          "descriptionKey": "ui.toolRail.agent.state.activeToolId"
        },
        {
          "name": "panelMode",
          "type": "'docked' | 'overlay' | 'full-screen'",
          "description": "How an open panel shows: docked beside the content, over it because the frame keeps a minimum width for main, or full screen on a phone.",
          "descriptionKey": "ui.agent.controlRoomRail.state.panelMode"
        }
      ],
      "actions": [
        {
          "name": "open",
          "safety": "read",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              }
            },
            "required": [
              "id"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "id": "inbox"
              },
              "note": "Open the inbox tool panel."
            }
          ],
          "description": "Open the given tool's panel.",
          "descriptionKey": "ui.toolRail.agent.actions.open"
        },
        {
          "name": "close",
          "safety": "read",
          "idempotent": true,
          "description": "Collapse the rail to its strip (no active tool).",
          "descriptionKey": "ui.toolRail.agent.actions.close"
        },
        {
          "name": "select_tool",
          "safety": "read",
          "argsType": "{ id: string | null }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "id"
            ]
          },
          "idempotent": true,
          "description": "Set the active tool by id (opens its panel), or pass null to collapse.",
          "descriptionKey": "ui.toolRail.agent.actions.selectTool"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "control-room-rail",
          "description": "Marks the ControlRoomRail wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop. Required to address a specific rail from the agent."
        },
        "item": {
          "attr": "data-tool-id",
          "description": "Stable tool id emitted on each strip IconButton. The active icon also carries data-active set to its id."
        }
      }
    },
    {
      "kind": "component",
      "id": "copy-field",
      "capabilities": [
        "copy"
      ],
      "state": [
        {
          "name": "value",
          "type": "string",
          "description": "The value displayed in the read-only field.",
          "descriptionKey": "ui.agent.copyField.state.value"
        },
        {
          "name": "copied",
          "type": "boolean",
          "description": "True for the brief window after a successful copy.",
          "descriptionKey": "ui.agent.copyField.state.copied"
        }
      ],
      "actions": [
        {
          "name": "copy",
          "safety": "write",
          "returns": "boolean",
          "returnsSchema": {
            "type": "boolean",
            "description": "True when the clipboard write succeeded."
          },
          "openWorld": true,
          "description": "Programmatically trigger the clipboard write.",
          "descriptionKey": "ui.agent.copyField.actions.copy"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "copy-field",
          "description": "Marks the CopyField root. The trailing button uses `aria-label` keyed off the copy / copied state."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop, when provided."
        }
      }
    },
    {
      "kind": "component",
      "id": "counter",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "counter",
          "description": "Marks the element as a kit Counter (numeric count badge)."
        }
      }
    },
    {
      "kind": "component",
      "id": "country-select",
      "capabilities": [
        "select_single",
        "set_value"
      ],
      "state": [
        {
          "name": "value",
          "type": "string | null",
          "description": "Selected ISO 3166-1 alpha-2 country code (lowercased), or null when nothing is selected.",
          "descriptionKey": "ui.agent.countrySelect.state.value"
        }
      ],
      "actions": [
        {
          "name": "set_value",
          "safety": "write",
          "argsType": "{ value: string | null }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "value": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "ISO 3166-1 alpha-2 country code (lowercased) to select, or null to clear."
              }
            },
            "required": [
              "value"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "value": "it"
              },
              "note": "Select Italy."
            }
          ],
          "description": "Set the selected country by ISO alpha-2 code.",
          "descriptionKey": "ui.agent.countrySelect.actions.setValue"
        },
        {
          "name": "clear_selection",
          "safety": "destructive",
          "idempotent": true,
          "description": "Clear the selected country.",
          "descriptionKey": "ui.agent.countrySelect.actions.clearSelection"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "country-select"
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        },
        "item": {
          "attr": "data-option-id",
          "description": "Each country option emits its alpha-2 code as data-option-id."
        }
      }
    },
    {
      "kind": "component",
      "id": "cycle-calculator",
      "capabilities": [
        "set_value"
      ],
      "state": [
        {
          "name": "inputs",
          "type": "{ lastPeriodStart: string | null, cycleLength: number | null, periodLength: number | null }",
          "description": "The three cycle inputs as entered — last-period start date (`yyyy-MM-dd`), average cycle length in days, and period (bleed) length in days. Null where unset.",
          "descriptionKey": "ui.agent.cycleCalculator.state.inputs"
        },
        {
          "name": "result",
          "type": "{ ovulation: string, fertileWindow: { start: string, end: string }, nextPeriod: string, periodRange: { start: string, end: string } | null, upcomingPeriods: string[] } | null",
          "description": "Computed prediction — ovulation date, fertile window, next period, current bleed range and the next few period starts, all `yyyy-MM-dd`. Null until a last-period date is set.",
          "descriptionKey": "ui.agent.cycleCalculator.state.result"
        }
      ],
      "actions": [
        {
          "name": "set_last_period",
          "safety": "write",
          "argsType": "{ date: string | null }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "date": {
                "oneOf": [
                  {
                    "type": "string",
                    "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                    "description": "Local calendar date, `yyyy-MM-dd`."
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Start date of the last period, or null to clear it. Must not be in the future."
              }
            },
            "required": [
              "date"
            ],
            "additionalProperties": false
          },
          "returns": "boolean",
          "returnsSchema": {
            "type": "boolean",
            "description": "True when the date was applied."
          },
          "idempotent": true,
          "errors": [
            "Returns false for an unparseable date or a date in the future — the on-screen DatePicker caps at today."
          ],
          "examples": [
            {
              "args": {
                "date": "2026-08-01"
              },
              "note": "Last period started 1 August."
            }
          ],
          "description": "Set the start date of the last period. This is the only required input — the prediction stays null without it.",
          "descriptionKey": "ui.agent.cycleCalculator.actions.setLastPeriod"
        },
        {
          "name": "set_cycle_length",
          "safety": "write",
          "argsType": "{ days: number | null }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "days": {
                "oneOf": [
                  {
                    "type": "integer",
                    "minimum": 20,
                    "maximum": 45
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Average cycle length in days (20–45), or null to fall back to the 28-day default."
              }
            },
            "required": [
              "days"
            ],
            "additionalProperties": false
          },
          "returns": "boolean",
          "returnsSchema": {
            "type": "boolean",
            "description": "True when the value was applied."
          },
          "idempotent": true,
          "errors": [
            "Returns false outside 20–45 days — the same bounds the on-screen NumberInput enforces."
          ],
          "description": "Set the average cycle length in days. Shifts ovulation, the fertile window and every upcoming period.",
          "descriptionKey": "ui.agent.cycleCalculator.actions.setCycleLength"
        },
        {
          "name": "set_period_length",
          "safety": "write",
          "argsType": "{ days: number | null }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "days": {
                "oneOf": [
                  {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 14
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Period (bleed) length in days (1–14), or null to omit the bleed range."
              }
            },
            "required": [
              "days"
            ],
            "additionalProperties": false
          },
          "returns": "boolean",
          "returnsSchema": {
            "type": "boolean",
            "description": "True when the value was applied."
          },
          "idempotent": true,
          "errors": [
            "Returns false outside 1–14 days — the same bounds the on-screen NumberInput enforces."
          ],
          "description": "Set the period (bleed) length in days. Optional — it only adds the current bleed range to the result.",
          "descriptionKey": "ui.agent.cycleCalculator.actions.setPeriodLength"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "cycle-calculator",
          "description": "Marks the CycleCalculator wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop. Also the registry key — without an `id` the instance does not register and only the DOM channel works."
        }
      }
    },
    {
      "kind": "component",
      "id": "dashboard-grid",
      "capabilities": [
        "edit_inline",
        "scroll"
      ],
      "state": [
        {
          "name": "layout",
          "type": "{ id: string, x: number, y: number, w: number, h: number }[]",
          "description": "Current widget geometry in cell units — ids and rectangles only, no widget content.",
          "descriptionKey": "ui.agent.dashboardGrid.state.layout"
        },
        {
          "name": "cols",
          "type": "number",
          "description": "Logical column count of the board.",
          "descriptionKey": "ui.agent.dashboardGrid.state.cols"
        },
        {
          "name": "editing",
          "type": "boolean",
          "description": "Whether edit mode is on. Move/resize actions are refused while it is off — the host app owns the toggle.",
          "descriptionKey": "ui.agent.dashboardGrid.state.editing"
        },
        {
          "name": "stacked",
          "type": "boolean",
          "description": "Whether the board is narrower than its stackBelow width and shows its widgets as one read-only column. Move/resize actions are unavailable while it is true, even in edit mode; the saved layout is unchanged.",
          "descriptionKey": "ui.agent.dashboardGrid.state.stacked"
        },
        {
          "name": "selectedId",
          "type": "string | null",
          "description": "The widget the host has marked (for example while its settings are open), or null. Set by the host, not by agents.",
          "descriptionKey": "ui.agent.dashboardGrid.state.selectedId"
        },
        {
          "name": "loadingIds",
          "type": "string[]",
          "description": "Ids of the widgets still waiting for their figures (the host set loading). Their bodies show placeholders, so read their values only once they leave this list. Set by the host, not by agents.",
          "descriptionKey": "ui.agent.dashboardGrid.state.loadingIds"
        }
      ],
      "actions": [
        {
          "name": "reveal_widget",
          "safety": "read",
          "argsType": "id",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "Widget id (see layout state)."
              }
            },
            "required": [
              "id"
            ]
          },
          "returns": "Promise<boolean> (revealed)",
          "returnsSchema": {
            "type": "boolean",
            "description": "True once the widget is in view; false if it has not appeared within a second."
          },
          "idempotent": true,
          "errors": [
            "Unknown or not yet rendered widget id: waits up to a second, then resolves false."
          ],
          "description": "Scroll a widget into view (its scrolling ancestor and the window) and highlight it briefly. Works in view and edit mode, and for a widget added a moment ago. Does not move focus.",
          "descriptionKey": "ui.agent.dashboardGrid.actions.revealWidget"
        },
        {
          "name": "move_widget",
          "safety": "write",
          "argsType": "id, x, y",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "Widget id (see layout state)."
              },
              "x": {
                "type": "integer",
                "minimum": 0,
                "description": "0-based logical column."
              },
              "y": {
                "type": "integer",
                "minimum": 0,
                "description": "0-based row."
              }
            },
            "required": [
              "id",
              "x",
              "y"
            ]
          },
          "returns": "boolean (accepted)",
          "returnsSchema": {
            "type": "boolean",
            "description": "True when applied; false when edit mode is off, the board is stacked, or the id is unknown."
          },
          "idempotent": true,
          "errors": [
            "Unavailable while the board is stacked (state stacked is true): returns false and changes nothing.",
            "Unavailable while edit mode is off: returns false.",
            "Unknown widget id: returns false."
          ],
          "description": "Move a widget to a cell. Out-of-bounds targets are clamped; colliding widgets are pushed down and the layout re-compacts. Refused while edit mode is off or the board is stacked.",
          "descriptionKey": "ui.agent.dashboardGrid.actions.moveWidget"
        },
        {
          "name": "resize_widget",
          "safety": "write",
          "argsType": "id, w, h",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "Widget id (see layout state)."
              },
              "w": {
                "type": "integer",
                "minimum": 1,
                "description": "Column span (≥ 1)."
              },
              "h": {
                "type": "integer",
                "minimum": 1,
                "description": "Row span (≥ 1)."
              }
            },
            "required": [
              "id",
              "w",
              "h"
            ]
          },
          "returns": "boolean (accepted)",
          "returnsSchema": {
            "type": "boolean",
            "description": "True when applied; false when edit mode is off, the board is stacked, or the id is unknown."
          },
          "idempotent": true,
          "errors": [
            "Unavailable while the board is stacked (state stacked is true): returns false and changes nothing.",
            "Unavailable while edit mode is off: returns false.",
            "Unknown widget id: returns false."
          ],
          "description": "Resize a widget to a span. Clamped to the grid and the widget’s min/max; colliding widgets are pushed down. Refused while edit mode is off or the board is stacked.",
          "descriptionKey": "ui.agent.dashboardGrid.actions.resizeWidget"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "dashboard-grid",
          "description": "Also carries data-stacked=\"true\" while the board shows one read-only column."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        },
        "item": {
          "attr": "data-widget-id",
          "description": "Each widget wrapper carries its layout id. While its figures load it also carries data-loading=\"true\" and aria-busy=\"true\"."
        }
      }
    },
    {
      "kind": "component",
      "id": "data-table",
      "capabilities": [
        "select_single",
        "select_multiple",
        "range_pick",
        "filter",
        "sort",
        "paginate"
      ],
      "state": [
        {
          "name": "selection",
          "type": "string[]",
          "description": "Row ids of currently-selected rows.",
          "descriptionKey": "ui.agent.dataTable.state.selection"
        },
        {
          "name": "filter",
          "type": "object",
          "description": "Current ag-grid filter model, keyed by column id.",
          "descriptionKey": "ui.agent.dataTable.state.filter"
        },
        {
          "name": "sort",
          "type": "Array<{ colId, sort }>",
          "description": "Active sort, in priority order.",
          "descriptionKey": "ui.agent.dataTable.state.sort"
        },
        {
          "name": "currentPage",
          "type": "number",
          "description": "Zero-indexed page number.",
          "descriptionKey": "ui.agent.dataTable.state.currentPage"
        },
        {
          "name": "expandedRowId",
          "type": "string | null",
          "description": "Id of the row whose inline detail is open (expandable row), or null.",
          "descriptionKey": "ui.agent.dataTable.state.expandedRowId"
        }
      ],
      "actions": [
        {
          "name": "select_rows",
          "safety": "read",
          "argsType": "{ ids: string[] }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "ids": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Row ids to select (replaces the current selection)."
              }
            },
            "required": [
              "ids"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "ids": [
                  "r-1",
                  "r-2"
                ]
              },
              "note": "Select the first two rows."
            }
          ],
          "description": "Replace the current selection with the given row ids.",
          "descriptionKey": "ui.agent.dataTable.actions.selectRows"
        },
        {
          "name": "select_range",
          "safety": "read",
          "argsType": "{ fromId: string, toId: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "fromId": {
                "type": "string",
                "description": "Start row id (inclusive)."
              },
              "toId": {
                "type": "string",
                "description": "End row id (inclusive)."
              }
            },
            "required": [
              "fromId",
              "toId"
            ]
          },
          "idempotent": true,
          "description": "Select every row between fromId and toId, inclusive, in current sort order.",
          "descriptionKey": "ui.agent.dataTable.actions.selectRange"
        },
        {
          "name": "clear_selection",
          "safety": "read",
          "idempotent": true,
          "description": "Deselect all rows.",
          "descriptionKey": "ui.agent.dataTable.actions.clearSelection"
        },
        {
          "name": "get_selection",
          "safety": "read",
          "returns": "string[]",
          "returnsSchema": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "idempotent": true,
          "description": "Return the row ids of the currently-selected rows.",
          "descriptionKey": "ui.agent.dataTable.actions.getSelection"
        },
        {
          "name": "apply_filter",
          "safety": "read",
          "argsType": "{ model: Record<string, unknown> }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "model": {
                "type": "object",
                "description": "ag-grid filter model keyed by column id. Opaque per-column filter shapes; replaces the current model.",
                "additionalProperties": true
              }
            },
            "required": [
              "model"
            ]
          },
          "idempotent": true,
          "description": "Replace the filter model with the given object.",
          "descriptionKey": "ui.agent.dataTable.actions.applyFilter"
        },
        {
          "name": "sort_by",
          "safety": "read",
          "argsType": "{ model: DataTableSortEntry[] }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "model": {
                "type": "array",
                "description": "Sort entries in priority order.",
                "items": {
                  "type": "object",
                  "properties": {
                    "colId": {
                      "type": "string",
                      "description": "Column id to sort by."
                    },
                    "sort": {
                      "enum": [
                        "asc",
                        "desc"
                      ],
                      "description": "Sort direction."
                    }
                  },
                  "required": [
                    "colId",
                    "sort"
                  ]
                }
              }
            },
            "required": [
              "model"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "model": [
                  {
                    "colId": "name",
                    "sort": "asc"
                  }
                ]
              },
              "note": "Sort by name ascending."
            }
          ],
          "description": "Replace the active sort with the given list (priority order).",
          "descriptionKey": "ui.agent.dataTable.actions.sortBy"
        },
        {
          "name": "go_to_page",
          "safety": "read",
          "argsType": "{ page: number }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "page": {
                "type": "integer",
                "minimum": 0,
                "description": "Zero-indexed page number."
              }
            },
            "required": [
              "page"
            ]
          },
          "idempotent": true,
          "description": "Navigate to the given zero-indexed page.",
          "descriptionKey": "ui.agent.dataTable.actions.goToPage"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "data-table",
          "description": "Marks the DataTable wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "gridId",
          "description": "Sourced from the gridId prop. Required to address a specific table from the agent."
        },
        "item": {
          "attr": "row-id",
          "description": "Native ag-grid row-id attribute on each rendered record row. When an expandable row is open, one extra full-width row with row-id `<parentId>::detail` is the accordion detail, not a record — its cell carries data-component=\"data-table-expanded-row\" and data-expanded-row-of=\"<parentId>\"; skip it when enumerating rows (isExpandedRowDetailId). Selection is performed via the curated handle, not by DOM mutation."
        }
      }
    },
    {
      "kind": "component",
      "id": "data-table-tabs",
      "capabilities": [
        "select_single",
        "view_change"
      ],
      "state": [
        {
          "name": "activeTabId",
          "type": "string | null",
          "description": "Id of the currently-active saved-filter tab.",
          "descriptionKey": "ui.agent.dataTableTabs.state.activeTabId"
        },
        {
          "name": "tabs",
          "type": "Array<{ id, label }>",
          "description": "The saved-filter tabs, in strip order (ids + labels).",
          "descriptionKey": "ui.agent.dataTableTabs.state.tabs"
        }
      ],
      "actions": [
        {
          "name": "select_tab",
          "safety": "read",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "Tab id to activate."
              }
            },
            "required": [
              "id"
            ]
          },
          "idempotent": true,
          "description": "Activate a saved-filter tab: snapshots the outgoing tab, applies the incoming filter model to the table.",
          "descriptionKey": "ui.agent.dataTableTabs.actions.selectTab"
        },
        {
          "name": "get_tabs",
          "safety": "read",
          "returns": "Array<{ id: string, label: string }>",
          "returnsSchema": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "label": {
                  "type": "string"
                }
              },
              "required": [
                "id",
                "label"
              ]
            }
          },
          "idempotent": true,
          "description": "Return the saved-filter tabs (ids + labels) in order.",
          "descriptionKey": "ui.agent.dataTableTabs.actions.getTabs"
        },
        {
          "name": "add_tab",
          "safety": "write",
          "argsType": "{ label?: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "label": {
                "type": "string",
                "description": "Display name for the new tab. Defaults to a numbered name."
              }
            },
            "required": []
          },
          "returns": "string",
          "returnsSchema": {
            "type": "string"
          },
          "idempotent": false,
          "description": "Add a new tab capturing the table's current filter model, and activate it. Returns the new tab id.",
          "descriptionKey": "ui.agent.dataTableTabs.actions.addTab"
        },
        {
          "name": "rename_tab",
          "safety": "write",
          "argsType": "{ id: string, label: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "Tab id to rename."
              },
              "label": {
                "type": "string",
                "description": "New display name."
              }
            },
            "required": [
              "id",
              "label"
            ]
          },
          "idempotent": true,
          "description": "Rename a saved-filter tab. No-op on locked tabs and empty labels.",
          "descriptionKey": "ui.agent.dataTableTabs.actions.renameTab"
        },
        {
          "name": "remove_tab",
          "safety": "destructive",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "Tab id to remove."
              }
            },
            "required": [
              "id"
            ]
          },
          "idempotent": true,
          "description": "Remove a saved-filter tab (its saved filter is lost). No-op on locked tabs and the last remaining tab.",
          "descriptionKey": "ui.agent.dataTableTabs.actions.removeTab"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "data-table-tabs"
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id"
        },
        "item": {
          "attr": "data-tab-id"
        }
      }
    },
    {
      "kind": "component",
      "id": "date-picker",
      "capabilities": [
        "select_single",
        "set_value",
        "open",
        "close"
      ],
      "state": [
        {
          "name": "value",
          "type": "iso-date",
          "description": "Currently-selected ISO date, or null.",
          "descriptionKey": "ui.agent.datePicker.state.value"
        },
        {
          "name": "isOpen",
          "type": "boolean",
          "description": "Whether the calendar popover is open.",
          "descriptionKey": "ui.agent.datePicker.state.isOpen"
        }
      ],
      "actions": [
        {
          "name": "set_date",
          "safety": "write",
          "argsType": "{ date: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "date": {
                "type": "string",
                "format": "date",
                "description": "ISO date, e.g. \"2026-06-23\"."
              }
            },
            "required": [
              "date"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "date": "2026-06-23"
              },
              "note": "Select 23 Jun 2026."
            }
          ],
          "description": "Select a specific date (ISO yyyy-mm-dd).",
          "descriptionKey": "ui.agent.datePicker.actions.setDate"
        },
        {
          "name": "clear",
          "safety": "destructive",
          "idempotent": true,
          "description": "Clear the selected date.",
          "descriptionKey": "ui.agent.datePicker.actions.clear"
        },
        {
          "name": "open",
          "safety": "read",
          "idempotent": true,
          "description": "Open the calendar popover.",
          "descriptionKey": "ui.agent.datePicker.actions.open"
        },
        {
          "name": "close",
          "safety": "read",
          "idempotent": true,
          "description": "Close the calendar popover.",
          "descriptionKey": "ui.agent.datePicker.actions.close"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "date-picker",
          "description": "Marks the DatePicker wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "date-range-picker",
      "capabilities": [
        "range_pick",
        "open",
        "close",
        "confirm",
        "dismiss",
        "set_value"
      ],
      "state": [
        {
          "name": "range",
          "type": "{ from: iso-date | null, to: iso-date | null }",
          "description": "Currently-selected ISO date range endpoints, each possibly null.",
          "descriptionKey": "ui.agent.dateRangePicker.state.range"
        },
        {
          "name": "isOpen",
          "type": "boolean",
          "description": "Whether the range calendar popover is open.",
          "descriptionKey": "ui.agent.dateRangePicker.state.isOpen"
        },
        {
          "name": "granularity",
          "type": "'day' | 'week' | 'month' | 'quarter' | null",
          "description": "Selected time granularity (Range Cockpit), or null when the control is disabled.",
          "descriptionKey": "ui.agent.dateRangePicker.state.granularity"
        },
        {
          "name": "compareRange",
          "type": "{ from: iso-date | null, to: iso-date | null } | null",
          "description": "Resolved comparison period when compare-to-previous-period is on, else null.",
          "descriptionKey": "ui.agent.dateRangePicker.state.compareRange"
        }
      ],
      "actions": [
        {
          "name": "set_range",
          "safety": "write",
          "argsType": "{ from: string, to: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "from": {
                "type": "string",
                "format": "date",
                "description": "ISO start date (inclusive)."
              },
              "to": {
                "type": "string",
                "format": "date",
                "description": "ISO end date (inclusive)."
              }
            },
            "required": [
              "from",
              "to"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "from": "2026-06-01",
                "to": "2026-06-30"
              },
              "note": "Select all of June 2026."
            }
          ],
          "description": "Replace the selected range with the given ISO endpoints.",
          "descriptionKey": "ui.agent.dateRangePicker.actions.setRange"
        },
        {
          "name": "clear",
          "safety": "destructive",
          "idempotent": true,
          "description": "Clear the selected range.",
          "descriptionKey": "ui.agent.dateRangePicker.actions.clear"
        },
        {
          "name": "open",
          "safety": "read",
          "idempotent": true,
          "description": "Open the range calendar popover.",
          "descriptionKey": "ui.agent.dateRangePicker.actions.open"
        },
        {
          "name": "close",
          "safety": "read",
          "idempotent": true,
          "description": "Close the range calendar popover.",
          "descriptionKey": "ui.agent.dateRangePicker.actions.close"
        },
        {
          "name": "apply",
          "safety": "write",
          "idempotent": true,
          "description": "Commit the current draft range (as the Apply / Done button).",
          "descriptionKey": "ui.agent.dateRangePicker.actions.apply"
        },
        {
          "name": "cancel",
          "safety": "read",
          "idempotent": true,
          "description": "Discard the draft and close without committing.",
          "descriptionKey": "ui.agent.dateRangePicker.actions.cancel"
        },
        {
          "name": "set_granularity",
          "safety": "write",
          "argsType": "{ granularity: 'day' | 'week' | 'month' | 'quarter' }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "granularity": {
                "type": "string",
                "enum": [
                  "day",
                  "week",
                  "month",
                  "quarter"
                ],
                "description": "Time grain to query the range at."
              }
            },
            "required": [
              "granularity"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "granularity": "month"
              },
              "note": "Query by month."
            }
          ],
          "description": "Set the time granularity (Range Cockpit).",
          "descriptionKey": "ui.agent.dateRangePicker.actions.setGranularity"
        },
        {
          "name": "toggle_compare",
          "safety": "write",
          "argsType": "{ enabled: boolean }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean",
                "description": "Whether to compare against the previous period."
              }
            },
            "required": [
              "enabled"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "enabled": true
              },
              "note": "Enable period comparison."
            }
          ],
          "description": "Turn compare-to-previous-period on or off (Range Cockpit).",
          "descriptionKey": "ui.agent.dateRangePicker.actions.toggleCompare"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "date-range-picker",
          "description": "Marks the DateRangePicker wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "date-time-picker",
      "capabilities": [
        "select_single",
        "set_value",
        "open",
        "close"
      ],
      "state": [
        {
          "name": "value",
          "type": "iso-datetime",
          "description": "Currently-selected ISO datetime, or null.",
          "descriptionKey": "ui.agent.dateTimePicker.state.value"
        },
        {
          "name": "isOpen",
          "type": "boolean",
          "description": "Whether the datetime popover is open.",
          "descriptionKey": "ui.agent.dateTimePicker.state.isOpen"
        }
      ],
      "actions": [
        {
          "name": "set_datetime",
          "safety": "write",
          "argsType": "{ datetime: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "datetime": {
                "type": "string",
                "format": "date-time",
                "description": "ISO datetime, e.g. \"2026-06-23T14:30:00Z\"."
              }
            },
            "required": [
              "datetime"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "datetime": "2026-06-23T14:30:00Z"
              },
              "note": "Select 23 Jun 2026, 14:30 UTC."
            }
          ],
          "description": "Select a specific datetime (ISO string).",
          "descriptionKey": "ui.agent.dateTimePicker.actions.setDatetime"
        },
        {
          "name": "clear",
          "safety": "destructive",
          "idempotent": true,
          "description": "Clear the selected datetime.",
          "descriptionKey": "ui.agent.dateTimePicker.actions.clear"
        },
        {
          "name": "open",
          "safety": "read",
          "idempotent": true,
          "description": "Open the datetime popover.",
          "descriptionKey": "ui.agent.dateTimePicker.actions.open"
        },
        {
          "name": "close",
          "safety": "read",
          "idempotent": true,
          "description": "Close the datetime popover.",
          "descriptionKey": "ui.agent.dateTimePicker.actions.close"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "date-time-picker",
          "description": "Marks the DateTimePicker wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "dependent-selector",
      "capabilities": [
        "select_single"
      ],
      "state": [
        {
          "name": "value",
          "type": "string",
          "description": "Id of the currently selected person, or empty string when none.",
          "descriptionKey": "ui.agent.dependentSelector.state.value"
        }
      ],
      "actions": [
        {
          "name": "set_value",
          "safety": "write",
          "argsType": "{ value: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "value": {
                "type": "string",
                "description": "Stable opaque id of the person row to select."
              }
            },
            "required": [
              "value"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "value": "person-2"
              },
              "note": "Select the second dependent."
            }
          ],
          "description": "Select the person row with the given id.",
          "descriptionKey": "ui.agent.dependentSelector.actions.setValue"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "dependent-selector",
          "description": "Marks the DependentSelector root (role=radiogroup)."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        },
        "item": {
          "attr": "data-option-id",
          "description": "Stable person id emitted on each rendered person row."
        }
      }
    },
    {
      "kind": "component",
      "id": "description-list",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "description-list",
          "description": "Marks the element as a kit DescriptionList."
        }
      }
    },
    {
      "kind": "component",
      "id": "dev-bypass-button",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "dev-bypass-button",
          "description": "Marks the development-only shortcut button. It must never appear in production HTML: the host renders it only when its server reports a development environment. The host pattern declares what the shortcut does and how safe it is."
        }
      }
    },
    {
      "kind": "component",
      "id": "dialog",
      "capabilities": [
        "open",
        "close",
        "dismiss"
      ],
      "state": [
        {
          "name": "isOpen",
          "type": "boolean",
          "description": "True when the dialog is currently open.",
          "descriptionKey": "ui.agent.dialog.state.isOpen"
        }
      ],
      "actions": [
        {
          "name": "open",
          "safety": "read",
          "idempotent": true,
          "description": "Open the dialog.",
          "descriptionKey": "ui.agent.dialog.actions.open"
        },
        {
          "name": "close",
          "safety": "read",
          "idempotent": true,
          "description": "Close the dialog. Reversible by reopening.",
          "descriptionKey": "ui.agent.dialog.actions.close"
        },
        {
          "name": "dismiss",
          "safety": "destructive",
          "idempotent": true,
          "description": "Dismiss the dialog. Loses any in-progress input that has not been committed.",
          "descriptionKey": "ui.agent.dialog.actions.dismiss"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "dialog"
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop on Dialog.Root."
        }
      }
    },
    {
      "kind": "component",
      "id": "document-preview",
      "capabilities": [],
      "state": [
        {
          "name": "kind",
          "type": "'pdf' | 'image' | 'metadata' | 'empty'",
          "description": "Which render branch is active: pdf, image, metadata (no inline preview), or empty (no document). Structural — never the document name.",
          "descriptionKey": "ui.agent.documentPreview.state.kind"
        }
      ],
      "actions": [
        {
          "name": "get_name",
          "safety": "phi",
          "returns": "string | undefined",
          "returnsSchema": {
            "type": [
              "string",
              "null"
            ]
          },
          "idempotent": true,
          "description": "Read the display name of the previewed document. May identify a patient (PHI).",
          "descriptionKey": "ui.agent.documentPreview.actions.getName"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "document-preview",
          "description": "Marks the DocumentPreview region."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "document-scanner",
      "capabilities": [
        "capture",
        "submit"
      ],
      "state": [
        {
          "name": "hasCapture",
          "type": "boolean",
          "description": "True when a captured or uploaded image is available.",
          "descriptionKey": "documentScanner.agent.state.hasCapture"
        },
        {
          "name": "phase",
          "type": "string",
          "description": "Current lifecycle phase of the scanner.",
          "descriptionKey": "documentScanner.agent.state.phase"
        }
      ],
      "actions": [
        {
          "name": "start_camera",
          "safety": "write",
          "idempotent": true,
          "errors": [
            "permission-denied",
            "no-camera",
            "not-readable",
            "insecure-context"
          ],
          "description": "Request camera permission and begin the live viewfinder.",
          "descriptionKey": "documentScanner.agent.actions.startCamera"
        },
        {
          "name": "capture",
          "safety": "write",
          "errors": [
            "capture-failed"
          ],
          "description": "Freeze the current viewfinder frame as a captured image.",
          "descriptionKey": "documentScanner.agent.actions.capture"
        },
        {
          "name": "submit",
          "safety": "write",
          "description": "Confirm the current capture and emit it via onConfirm.",
          "descriptionKey": "documentScanner.agent.actions.confirm"
        },
        {
          "name": "retake",
          "safety": "destructive",
          "description": "Discard the current capture and return to capture.",
          "descriptionKey": "documentScanner.agent.actions.retake"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "document-scanner",
          "description": "Marks the DocumentScanner wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "dropdown-menu",
      "capabilities": [
        "open",
        "close",
        "set_value"
      ],
      "state": [
        {
          "name": "isOpen",
          "type": "boolean",
          "description": "True when the menu is currently open.",
          "descriptionKey": "ui.agent.dropdownMenu.state.isOpen"
        },
        {
          "name": "settings",
          "type": "Array<{ setting: string; kind: \"choice\" | \"switch\"; value?: string; options?: string[]; checked?: boolean; disabled: boolean }>",
          "description": "The menu's named settings rows and their current values: choice rows with the selected value and every option's value, switch rows with whether they are on. Rows are listed only while the menu is open; open it first to read them.",
          "descriptionKey": "ui.agent.dropdownMenu.state.settings"
        }
      ],
      "actions": [
        {
          "name": "open",
          "safety": "read",
          "idempotent": true,
          "description": "Open the menu.",
          "descriptionKey": "ui.agent.dropdownMenu.actions.open"
        },
        {
          "name": "close",
          "safety": "read",
          "idempotent": true,
          "description": "Close the menu.",
          "descriptionKey": "ui.agent.dropdownMenu.actions.close"
        },
        {
          "name": "set_value",
          "safety": "write",
          "argsType": "{ setting: string; value: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "setting": {
                "type": "string",
                "description": "The row's name (its data-setting attribute)."
              },
              "value": {
                "type": "string",
                "description": "One of the row's option values."
              }
            },
            "required": [
              "setting",
              "value"
            ]
          },
          "idempotent": true,
          "errors": [
            "No choice row with that name in this menu",
            "The value is not one of the options, or it or the row is disabled"
          ],
          "examples": [
            {
              "args": {
                "setting": "slotDensity",
                "value": "comfortable"
              },
              "note": "Calendar display settings: switch to comfortable rows."
            }
          ],
          "description": "Pick an option on a named choice row (ChoiceSub), as clicking it would. A closed menu opens for the moment and closes again.",
          "descriptionKey": "ui.agent.dropdownMenu.actions.setValue"
        },
        {
          "name": "set_checked",
          "safety": "write",
          "argsType": "{ setting: string; checked: boolean }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "setting": {
                "type": "string",
                "description": "The row's name (its data-setting attribute)."
              },
              "checked": {
                "type": "boolean"
              }
            },
            "required": [
              "setting",
              "checked"
            ]
          },
          "idempotent": true,
          "errors": [
            "No switch row with that name in this menu",
            "The row is disabled"
          ],
          "examples": [
            {
              "args": {
                "setting": "zebraRows",
                "checked": true
              },
              "note": "Calendar display settings: turn zebra rows on."
            }
          ],
          "description": "Turn a named switch row (SwitchItem) on or off, as clicking it would. A closed menu opens for the moment and closes again.",
          "descriptionKey": "ui.agent.dropdownMenu.actions.setChecked"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "dropdown-menu"
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop on DropdownMenu.Root."
        },
        "item": {
          "attr": "data-setting",
          "sourceProp": "name",
          "description": "On a ChoiceSub or SwitchItem row given a name: the setting that set_value / set_checked address."
        }
      }
    },
    {
      "kind": "component",
      "id": "due-date-calculator",
      "capabilities": [
        "set_value"
      ],
      "state": [
        {
          "name": "inputs",
          "type": "{ method: string, referenceDate: string | null, cycleLength: number | null, embryoAge: 3 | 5, crlMm: number | null, scanDate: string | null, asOfDate: string }",
          "description": "The dating inputs as entered — method, its reference date, cycle length (LMP), embryo age (IVF), the optional CRL + scan date, and the evaluation date. Dates are `yyyy-MM-dd`. Read this to see which method a reference date will be interpreted under.",
          "descriptionKey": "ui.agent.dueDateCalculator.state.inputs"
        },
        {
          "name": "result",
          "type": "{ dueDate: string, gestationalStart: string, gestationalAge: { weeks: number, days: number, totalDays: number } | null, trimester: string } | null",
          "description": "Computed estimated delivery date, the GA day-0 anchor after any CRL re-dating, the gestational age as of the evaluation date, and the trimester band. Null until a reference date is set.",
          "descriptionKey": "ui.agent.dueDateCalculator.state.result"
        }
      ],
      "actions": [
        {
          "name": "set_method",
          "safety": "write",
          "argsType": "{ method: 'lmp' | 'conception' | 'ivf' }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "method": {
                "enum": [
                  "lmp",
                  "conception",
                  "ivf"
                ],
                "description": "Which anchor to date from — last menstrual period, conception, or IVF transfer."
              }
            },
            "required": [
              "method"
            ],
            "additionalProperties": false
          },
          "returns": "boolean",
          "returnsSchema": {
            "type": "boolean",
            "description": "True when the method was applied."
          },
          "idempotent": true,
          "errors": [
            "Returns false for a method outside the three supported anchors."
          ],
          "deprecated": "Superseded by the `pregnancy-dating` adapter.",
          "description": "Choose which anchor the pregnancy is dated from. The reference date is kept and re-interpreted under the new method, so set the method first.",
          "descriptionKey": "ui.agent.dueDateCalculator.actions.setMethod"
        },
        {
          "name": "set_reference_date",
          "safety": "write",
          "argsType": "{ date: string | null }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "date": {
                "oneOf": [
                  {
                    "type": "string",
                    "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                    "description": "Local calendar date, `yyyy-MM-dd`."
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "The date the active method anchors on — LMP, conception, or transfer — or null to clear it. Must not be in the future."
              }
            },
            "required": [
              "date"
            ],
            "additionalProperties": false
          },
          "returns": "boolean",
          "returnsSchema": {
            "type": "boolean",
            "description": "True when the date was applied."
          },
          "idempotent": true,
          "errors": [
            "Returns false for an unparseable date or a date in the future — the on-screen DatePicker caps at today."
          ],
          "examples": [
            {
              "args": {
                "date": "2026-01-12"
              },
              "note": "Under the default LMP method, a last period starting 12 January."
            }
          ],
          "deprecated": "Superseded by the `pregnancy-dating` adapter.",
          "description": "Set the reference date for the active method. This is the only required input — the result stays null without it.",
          "descriptionKey": "ui.agent.dueDateCalculator.actions.setReferenceDate"
        },
        {
          "name": "set_cycle_length",
          "safety": "write",
          "argsType": "{ days: number | null }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "days": {
                "oneOf": [
                  {
                    "type": "integer",
                    "minimum": 20,
                    "maximum": 45
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Average cycle length in days (20–45), or null to fall back to the 28-day default."
              }
            },
            "required": [
              "days"
            ],
            "additionalProperties": false
          },
          "returns": "boolean",
          "returnsSchema": {
            "type": "boolean",
            "description": "True when the value was applied."
          },
          "idempotent": true,
          "errors": [
            "Returns false outside 20–45 days — the same bounds the on-screen NumberInput enforces.",
            "Applies but changes nothing unless the method is `lmp`, and is ignored once a CRL re-dating is confirmed."
          ],
          "deprecated": "Superseded by the `pregnancy-dating` adapter.",
          "description": "LMP method only — set the average cycle length, which shifts Naegele dating off the 28-day assumption.",
          "descriptionKey": "ui.agent.dueDateCalculator.actions.setCycleLength"
        },
        {
          "name": "set_embryo_age",
          "safety": "write",
          "argsType": "{ days: 3 | 5 }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "days": {
                "enum": [
                  3,
                  5
                ],
                "description": "Embryo age at transfer in days — 3 (cleavage) or 5 (blastocyst)."
              }
            },
            "required": [
              "days"
            ],
            "additionalProperties": false
          },
          "returns": "boolean",
          "returnsSchema": {
            "type": "boolean",
            "description": "True when the value was applied."
          },
          "idempotent": true,
          "errors": [
            "Returns false for any value other than 3 or 5.",
            "Applies but changes nothing unless the method is `ivf`."
          ],
          "deprecated": "Superseded by the `pregnancy-dating` adapter.",
          "description": "IVF method only — set the embryo age at transfer, which offsets the transfer date back to a notional LMP.",
          "descriptionKey": "ui.agent.dueDateCalculator.actions.setEmbryoAge"
        },
        {
          "name": "set_crl",
          "safety": "write",
          "argsType": "{ crlMm?: number | null, scanDate?: string | null }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "crlMm": {
                "oneOf": [
                  {
                    "type": "number",
                    "exclusiveMinimum": 0
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Crown-rump length in millimetres, or null to clear it."
              },
              "scanDate": {
                "oneOf": [
                  {
                    "type": "string",
                    "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Date of the CRL scan (`yyyy-MM-dd`, not in the future), or null to clear it."
              }
            },
            "additionalProperties": false
          },
          "returns": "boolean",
          "returnsSchema": {
            "type": "boolean",
            "description": "True when the measurement was applied."
          },
          "idempotent": true,
          "errors": [
            "Returns false and writes nothing when the length is not positive or the scan date is unparseable or in the future — the payload applies all-or-nothing.",
            "Re-dating only happens under the `lmp` method, and only when both the length and the scan date are set."
          ],
          "examples": [
            {
              "args": {
                "crlMm": 42,
                "scanDate": "2026-02-20"
              },
              "note": "A first-trimester CRL that may re-date the pregnancy per ACOG CO 700."
            }
          ],
          "deprecated": "Superseded by the `pregnancy-dating` adapter.",
          "description": "LMP method only — set the first-trimester crown-rump length and its scan date. When the two disagree with the LMP beyond the ACOG threshold, the scan re-dates the pregnancy and overrides cycle length.",
          "descriptionKey": "ui.agent.dueDateCalculator.actions.setCrl"
        },
        {
          "name": "set_as_of_date",
          "safety": "write",
          "argsType": "{ date: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "date": {
                "type": "string",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                "description": "Date to evaluate gestational age and trimester against, `yyyy-MM-dd`. May be in the future to project forward."
              }
            },
            "required": [
              "date"
            ],
            "additionalProperties": false
          },
          "returns": "boolean",
          "returnsSchema": {
            "type": "boolean",
            "description": "True when the date was applied."
          },
          "idempotent": true,
          "errors": [
            "Returns false for an unparseable date."
          ],
          "examples": [
            {
              "args": {
                "date": "2026-09-15"
              },
              "note": "Project gestational age forward to an upcoming appointment."
            }
          ],
          "deprecated": "Superseded by the `pregnancy-dating` adapter.",
          "description": "Set the date gestational age, trimester and the antenatal schedule are evaluated against. Defaults to today; the estimated delivery date itself does not depend on it.",
          "descriptionKey": "ui.agent.dueDateCalculator.actions.setAsOfDate"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "due-date-calculator",
          "description": "Marks the DueDateCalculator wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop. Also the registry key — without an `id` the instance does not register and the handle-driven actions/state are unreachable."
        }
      }
    },
    {
      "kind": "component",
      "id": "editable-description",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "editable-description",
          "description": "Marks the element as a kit EditableDescription."
        },
        "item": {
          "attr": "data-editable-description-line",
          "description": "One visible description line."
        }
      }
    },
    {
      "kind": "component",
      "id": "editor-overlay",
      "capabilities": [
        "dismiss",
        "close"
      ],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "editor-overlay",
          "description": "Marks the EditorOverlay region wrapper. Present only while `open` is true — its absence IS the closed state."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the optional `id` prop — tells two mounted overlays apart."
        }
      }
    },
    {
      "kind": "component",
      "id": "email-input",
      "capabilities": [],
      "state": [
        {
          "name": "value",
          "type": "string",
          "description": "The current email address typed into the field.",
          "descriptionKey": "ui.agent.emailInput.state.value"
        },
        {
          "name": "isValid",
          "type": "boolean",
          "description": "True when the value is non-empty AND parses as a valid email per RFC 5322.",
          "descriptionKey": "ui.agent.emailInput.state.isValid"
        }
      ],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "email-input",
          "description": "Marks the EmailInput wrapper. The inline error element carries `role=\"alert\"` when validation fails."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop, when provided."
        }
      }
    },
    {
      "kind": "component",
      "id": "empty-state",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "empty-state",
          "description": "Marks the EmptyState wrapper. CTAs inside are kit Buttons / Links and carry their own DOM hooks."
        }
      }
    },
    {
      "kind": "component",
      "id": "entity-summary",
      "capabilities": [
        "close"
      ],
      "state": [
        {
          "name": "sections",
          "type": "Array<{ id: string; heading: string; tone: \"default\" | \"attention\"; itemCount: number }>",
          "description": "Structural section list — ids, fixed category headings, tone and item counts. Never the entity name or the bullet items (both PHI).",
          "descriptionKey": "ui.agent.entitySummary.state.sections"
        },
        {
          "name": "generatedAtIso",
          "type": "string | undefined",
          "description": "ISO-8601 instant the brief was generated, when known.",
          "descriptionKey": "ui.agent.entitySummary.state.generatedAtIso"
        }
      ],
      "actions": [
        {
          "name": "regenerate",
          "safety": "write",
          "openWorld": true,
          "description": "Request the host to regenerate the AI brief. No-op when the regenerate affordance is not available.",
          "descriptionKey": "ui.agent.entitySummary.actions.regenerate"
        },
        {
          "name": "close",
          "safety": "read",
          "idempotent": true,
          "description": "Dismiss the summary panel. No-op when the close affordance is not available (e.g. docked in the rail).",
          "descriptionKey": "ui.agent.entitySummary.actions.close"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "entity-summary",
          "description": "Marks the EntitySummary panel region."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop. Required to address a specific summary panel from the agent."
        }
      }
    },
    {
      "kind": "component",
      "id": "error-boundary",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "error-boundary",
          "description": "Wraps whatever the boundary shows once it has caught — the default face or a host fallback alike. Present only after a catch, so its absence means the tree below is healthy."
        }
      }
    },
    {
      "kind": "component",
      "id": "error-summary",
      "capabilities": [
        "navigate"
      ],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "error-summary",
          "description": "Marks the ErrorSummary. Present only while the form has problems to list; its heading names it and each list item is one problem."
        },
        "item": {
          "attr": "data-error-field",
          "description": "Each problem emits its field's name (`errors[].field`) as data-error-field: not data-field, which a form puts on the field itself. Its link (`data-action=\"go-to-field\"`) points at the field by id and moves focus to the field's control. An item without a link belongs to no single field."
        }
      }
    },
    {
      "kind": "component",
      "id": "face-scheme",
      "capabilities": [
        "pick",
        "set_value",
        "edit_inline",
        "view_change"
      ],
      "state": [
        {
          "name": "activeView",
          "type": "string",
          "description": "Id of the currently displayed view (front / profile-left / profile-right).",
          "descriptionKey": "ui.agent.faceScheme.state.activeView"
        },
        {
          "name": "zoom",
          "type": "number",
          "description": "Current figure zoom factor (1 = the base framing; up to 8). Only meaningful when the surface enables `zoomable`.",
          "descriptionKey": "ui.agent.faceScheme.state.zoom"
        },
        {
          "name": "chart",
          "type": "Record<string, string[]>",
          "description": "Current face chart — the finding types recorded on each zone, keyed by zone id. Free-text notes and the patient photo are not exposed here.",
          "descriptionKey": "ui.agent.faceScheme.state.chart"
        },
        {
          "name": "markedZones",
          "type": "string[]",
          "description": "Zone ids carrying at least one finding.",
          "descriptionKey": "ui.agent.faceScheme.state.markedZones"
        },
        {
          "name": "activeTool",
          "type": "string | null",
          "description": "The active free-form drawing tool (marker / pen / highlighter / arrow / line / rect / ellipse / text), or null when none is selected.",
          "descriptionKey": "ui.agent.faceScheme.state.activeTool"
        },
        {
          "name": "annotationCounts",
          "type": "Record<string, number>",
          "description": "Count of free-form annotations on the active view, keyed by kind (marker / pen / highlighter / arrow / line / rect / ellipse / text). Never includes coordinates or the free-text of a text callout.",
          "descriptionKey": "ui.agent.faceScheme.state.annotationCounts"
        },
        {
          "name": "selectedAnnotation",
          "type": "{ id: string; kind: string } | null",
          "description": "The selected free-form annotation on the active view (id + kind), or null when nothing is selected. Never includes coordinates or the free-text of a text callout.",
          "descriptionKey": "ui.agent.faceScheme.state.selectedAnnotation"
        },
        {
          "name": "selectedZones",
          "type": "string[]",
          "description": "Zone ids in the multi-selection (zoneSelect=\"multi\") — the set a bulk finding apply targets. Empty when the mode is off or nothing is selected.",
          "descriptionKey": "ui.agent.faceScheme.state.selectedZones"
        },
        {
          "name": "annotationZones",
          "type": "Record<string, number>",
          "description": "Count of free-form annotations on the active view keyed by their linked zone id ('unassigned' = outside every zone or not yet assessed). Counts only — never coordinates or text.",
          "descriptionKey": "ui.agent.faceScheme.state.annotationZones"
        }
      ],
      "actions": [
        {
          "name": "focus_zone",
          "safety": "read",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "Face-zone id (e.g. 'glabella', 'nasolabialFold', 'forehead', 'mandibularAngleLeft' on the front view; 'cheekbone', 'masseter', 'chin' on a profile view)."
              }
            },
            "required": [
              "id"
            ]
          },
          "idempotent": true,
          "description": "Move focus to a specific face zone by id.",
          "descriptionKey": "ui.agent.faceScheme.actions.focusZone"
        },
        {
          "name": "get_zone",
          "safety": "read",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "Face-zone id (e.g. 'glabella', 'nasolabialFold', 'forehead', 'mandibularAngleLeft' on the front view; 'cheekbone', 'masseter', 'chin' on a profile view)."
              }
            },
            "required": [
              "id"
            ]
          },
          "returns": "string[]",
          "returnsSchema": {
            "type": "array",
            "items": {
              "enum": [
                "observation",
                "treatment",
                "concern",
                "note"
              ]
            }
          },
          "idempotent": true,
          "description": "Read the finding types recorded on one zone (notes are not returned).",
          "descriptionKey": "ui.agent.faceScheme.actions.getZone"
        },
        {
          "name": "zones_with",
          "safety": "read",
          "argsType": "{ finding: FaceFindingType }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "finding": {
                "enum": [
                  "observation",
                  "treatment",
                  "concern",
                  "note"
                ]
              }
            },
            "required": [
              "finding"
            ]
          },
          "returns": "string[]",
          "returnsSchema": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "Face-zone id (e.g. 'glabella', 'nasolabialFold', 'forehead', 'mandibularAngleLeft' on the front view; 'cheekbone', 'masseter', 'chin' on a profile view)."
            }
          },
          "idempotent": true,
          "description": "List the zone ids carrying a given finding type.",
          "descriptionKey": "ui.agent.faceScheme.actions.zonesWith"
        },
        {
          "name": "set_finding",
          "safety": "write",
          "argsType": "{ id: string; finding: FaceFindingType; note?: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "Face-zone id (e.g. 'glabella', 'nasolabialFold', 'forehead', 'mandibularAngleLeft' on the front view; 'cheekbone', 'masseter', 'chin' on a profile view)."
              },
              "finding": {
                "enum": [
                  "observation",
                  "treatment",
                  "concern",
                  "note"
                ]
              },
              "note": {
                "type": "string"
              }
            },
            "required": [
              "id",
              "finding"
            ]
          },
          "idempotent": true,
          "description": "Record a finding on a zone, with an optional free-text note.",
          "descriptionKey": "ui.agent.faceScheme.actions.setFinding"
        },
        {
          "name": "remove_finding",
          "safety": "write",
          "argsType": "{ id: string; finding: FaceFindingType }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "Face-zone id (e.g. 'glabella', 'nasolabialFold', 'forehead', 'mandibularAngleLeft' on the front view; 'cheekbone', 'masseter', 'chin' on a profile view)."
              },
              "finding": {
                "enum": [
                  "observation",
                  "treatment",
                  "concern",
                  "note"
                ]
              }
            },
            "required": [
              "id",
              "finding"
            ]
          },
          "idempotent": true,
          "description": "Remove a single finding from a zone.",
          "descriptionKey": "ui.agent.faceScheme.actions.removeFinding"
        },
        {
          "name": "clear_zone",
          "safety": "destructive",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "Face-zone id (e.g. 'glabella', 'nasolabialFold', 'forehead', 'mandibularAngleLeft' on the front view; 'cheekbone', 'masseter', 'chin' on a profile view)."
              }
            },
            "required": [
              "id"
            ]
          },
          "idempotent": true,
          "description": "Clear every finding from a zone.",
          "descriptionKey": "ui.agent.faceScheme.actions.clearZone"
        },
        {
          "name": "auto_align",
          "safety": "write",
          "argsType": "{}",
          "argsSchema": {
            "type": "object",
            "properties": {}
          },
          "idempotent": true,
          "description": "Run the on-device detector to align the zone overlay to the patient photo (works on the active view — front or profile). No-op if detection is disabled or no face is found.",
          "descriptionKey": "ui.agent.faceScheme.actions.autoAlign"
        },
        {
          "name": "set_view",
          "safety": "write",
          "argsType": "{ view: FaceViewId }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "view": {
                "type": "string",
                "enum": [
                  "front",
                  "profile-left",
                  "profile-right"
                ],
                "description": "Active view id: 'front', 'profile-left', or 'profile-right'."
              }
            },
            "required": [
              "view"
            ]
          },
          "idempotent": true,
          "description": "Switch the active view ('front' / 'profile-left' / 'profile-right'). Each view renders a different zone set, so switch before focusing a zone that belongs to another view.",
          "descriptionKey": "ui.agent.faceScheme.actions.setView"
        },
        {
          "name": "set_zoom",
          "safety": "write",
          "argsType": "{ factor: number }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "factor": {
                "type": "number",
                "minimum": 1,
                "maximum": 8
              }
            },
            "required": [
              "factor"
            ]
          },
          "idempotent": true,
          "description": "Set the figure zoom factor (1 = reset to the base framing, clamped to 1–8), anchored on the window centre. No-op unless the surface enables `zoomable`.",
          "descriptionKey": "ui.agent.faceScheme.actions.setZoom"
        },
        {
          "name": "set_tool",
          "safety": "write",
          "argsType": "{ tool: FaceAnnotationTool | 'none' }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "tool": {
                "type": "string",
                "enum": [
                  "none",
                  "marker",
                  "pen",
                  "highlighter",
                  "arrow",
                  "line",
                  "rect",
                  "ellipse",
                  "text"
                ],
                "description": "Drawing tool: 'none' (off), 'marker', 'pen', 'highlighter', 'arrow', 'line', 'rect', 'ellipse', or 'text'."
              }
            },
            "required": [
              "tool"
            ]
          },
          "idempotent": true,
          "description": "Select the active free-form drawing tool ('none' turns drawing off; pointer then falls through to zone selection).",
          "descriptionKey": "ui.agent.faceScheme.actions.setTool"
        },
        {
          "name": "undo_annotation",
          "safety": "write",
          "argsType": "{}",
          "argsSchema": {
            "type": "object",
            "properties": {}
          },
          "description": "Remove the most-recently-added free-form annotation from the active view.",
          "descriptionKey": "ui.agent.faceScheme.actions.undoAnnotation"
        },
        {
          "name": "select_annotation",
          "safety": "read",
          "argsType": "{ id: string | null }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Annotation id on the active view (null clears the selection). Unknown ids are ignored."
              }
            },
            "required": [
              "id"
            ]
          },
          "idempotent": true,
          "description": "Select a free-form annotation on the active view by id (null clears). Selection reveals the mark and enables its panel affordances (delete / recolour).",
          "descriptionKey": "ui.agent.faceScheme.actions.selectAnnotation"
        },
        {
          "name": "set_annotation_zone",
          "safety": "write",
          "argsType": "{ id: string; zone: string | null }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "Annotation id on the active view."
              },
              "zone": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Zone id to link, or null to unlink ('no zone')."
              }
            },
            "required": [
              "id",
              "zone"
            ]
          },
          "idempotent": true,
          "description": "Link a free-form annotation to a face zone by id (null unlinks it). Unknown annotation ids are ignored. New drawings are auto-linked to the zone under them; this re-assigns marks drawn outside every zone.",
          "descriptionKey": "ui.agent.faceScheme.actions.setAnnotationZone"
        },
        {
          "name": "select_zones",
          "safety": "read",
          "argsType": "{ ids: string[] }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "ids": {
                "type": "array",
                "items": {
                  "type": "string",
                  "description": "Face-zone id (e.g. 'glabella', 'nasolabialFold', 'forehead', 'mandibularAngleLeft' on the front view; 'cheekbone', 'masseter', 'chin' on a profile view)."
                },
                "description": "Zone ids to select (replaces the current selection; [] clears)."
              }
            },
            "required": [
              "ids"
            ]
          },
          "idempotent": true,
          "description": "Replace the zone multi-selection (zoneSelect=\"multi\"). Selection is UI state only — pair with set_finding_bulk to record a finding on the selected zones, or pass ids straight to set_finding_bulk instead.",
          "descriptionKey": "ui.agent.faceScheme.actions.selectZones"
        },
        {
          "name": "set_finding_bulk",
          "safety": "write",
          "argsType": "{ ids: string[]; finding: FaceFindingType; note?: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "ids": {
                "type": "array",
                "items": {
                  "type": "string",
                  "description": "Face-zone id (e.g. 'glabella', 'nasolabialFold', 'forehead', 'mandibularAngleLeft' on the front view; 'cheekbone', 'masseter', 'chin' on a profile view)."
                },
                "description": "Zone ids to record the finding on."
              },
              "finding": {
                "enum": [
                  "observation",
                  "treatment",
                  "concern",
                  "note"
                ]
              },
              "note": {
                "type": "string"
              }
            },
            "required": [
              "ids",
              "finding"
            ]
          },
          "idempotent": true,
          "description": "Record one finding on several zones in a single chart commit (the multi-zone diagnosis path). Zones already carrying the finding are left as they are; the optional note lands only where the finding is newly added.",
          "descriptionKey": "ui.agent.faceScheme.actions.setFindingBulk"
        },
        {
          "name": "clear_annotations",
          "safety": "destructive",
          "argsType": "{}",
          "argsSchema": {
            "type": "object",
            "properties": {}
          },
          "idempotent": true,
          "description": "Clear every free-form annotation from the active view. Zone findings are untouched.",
          "descriptionKey": "ui.agent.faceScheme.actions.clearAnnotations"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "face-scheme"
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        },
        "item": {
          "attr": "data-zone",
          "description": "Each clickable zone `<g>` carries its zone id as `data-zone` (plus `data-side` for the anatomical side, and `data-zone-selected=\"true\"` while in the multi-selection). Each free-form annotation `<g>` carries `data-annotation` (its id), `data-annotation-kind`, `data-annotation-zone` (its linked zone id, when linked), and `data-selected=\"true\"` while selected. The root `<div>` carries the active view id as `data-view` — only the zones for the active view are in the DOM."
        }
      }
    },
    {
      "kind": "component",
      "id": "fetal-weight",
      "capabilities": [
        "set_value"
      ],
      "state": [
        {
          "name": "biometry",
          "type": "{ bpdMm: number | null, hcMm: number | null, acMm: number | null, flMm: number | null }",
          "description": "The four ultrasound measurements as entered, in millimetres — biparietal diameter, head circumference, abdominal circumference and femur length. Null where unset. Read this to see why a result is still null.",
          "descriptionKey": "ui.agent.fetalWeight.state.biometry"
        },
        {
          "name": "result",
          "type": "{ grams: number, method: 'hadlock4' | 'hadlock1' } | null",
          "description": "Estimated fetal weight in grams and which Hadlock regression produced it — `hadlock4` when all four measurements are present, `hadlock1` from AC + FL alone. Null until AC and FL are both set.",
          "descriptionKey": "ui.agent.fetalWeight.state.result"
        }
      ],
      "actions": [
        {
          "name": "set_biometry",
          "safety": "write",
          "argsType": "{ bpdMm?: number | null, hcMm?: number | null, acMm?: number | null, flMm?: number | null }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "bpdMm": {
                "oneOf": [
                  {
                    "type": "number",
                    "exclusiveMinimum": 0
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Biparietal diameter in millimetres, or null to clear it."
              },
              "hcMm": {
                "oneOf": [
                  {
                    "type": "number",
                    "exclusiveMinimum": 0
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Head circumference in millimetres, or null to clear it."
              },
              "acMm": {
                "oneOf": [
                  {
                    "type": "number",
                    "exclusiveMinimum": 0
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Abdominal circumference in millimetres, or null to clear it."
              },
              "flMm": {
                "oneOf": [
                  {
                    "type": "number",
                    "exclusiveMinimum": 0
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Femur length in millimetres, or null to clear it."
              }
            },
            "additionalProperties": false
          },
          "returns": "boolean",
          "returnsSchema": {
            "type": "boolean",
            "description": "True when the measurements were applied."
          },
          "idempotent": true,
          "errors": [
            "Returns false and writes nothing when any supplied measurement is not a positive number — the payload applies all-or-nothing."
          ],
          "examples": [
            {
              "args": {
                "bpdMm": 85,
                "hcMm": 310,
                "acMm": 300,
                "flMm": 62
              },
              "note": "Full biometry around 32 weeks → the Hadlock 4-parameter estimate."
            },
            {
              "args": {
                "acMm": 300,
                "flMm": 62
              },
              "note": "AC + FL only — the minimum for an estimate, via Hadlock 1."
            }
          ],
          "description": "Set any subset of the ultrasound biometry in millimetres. Omitted measurements are left unchanged; an explicit null clears one. AC and FL are the minimum for an estimate.",
          "descriptionKey": "ui.agent.fetalWeight.actions.setBiometry"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "fetal-weight",
          "description": "Marks the FetalWeight calculator (estimated fetal weight from ultrasound biometry)."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop. Also the registry key — without an `id` the instance does not register and the handle-driven action/state are unreachable."
        }
      }
    },
    {
      "kind": "component",
      "id": "field-array",
      "capabilities": [
        "edit_inline"
      ],
      "state": [
        {
          "name": "count",
          "type": "number",
          "description": "Number of rows currently rendered.",
          "descriptionKey": "ui.agent.fieldArray.state.count"
        }
      ],
      "actions": [
        {
          "name": "add",
          "safety": "write",
          "description": "Append a new row.",
          "descriptionKey": "ui.agent.fieldArray.actions.add"
        },
        {
          "name": "remove",
          "safety": "destructive",
          "argsType": "{ index: number }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "index": {
                "type": "number"
              }
            },
            "required": [
              "index"
            ]
          },
          "description": "Remove the row at the given index.",
          "descriptionKey": "ui.agent.fieldArray.actions.remove"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "field-array",
          "description": "Marks the FieldArray fieldset."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "file-manager",
      "capabilities": [
        "select_multiple",
        "navigate",
        "filter",
        "open"
      ],
      "state": [
        {
          "name": "selection",
          "type": "string[]",
          "description": "Item ids of the currently-selected files and folders.",
          "descriptionKey": "ui.agent.fileManager.state.selection"
        },
        {
          "name": "currentFolder",
          "type": "string | null",
          "description": "Id of the folder being viewed, or null for the root.",
          "descriptionKey": "ui.agent.fileManager.state.currentFolder"
        },
        {
          "name": "typeFilter",
          "type": "string[]",
          "description": "Active document-type filter applied to the open folder (empty = no filter).",
          "descriptionKey": "ui.agent.fileManager.state.typeFilter"
        },
        {
          "name": "items",
          "type": "Array<{ id, kind, parentId, size, updatedAt, documentType, signatureStatus }>",
          "description": "Structural metadata for every item — ids, kinds, sizes, dates, document types, signature states. Names are PHI and never included; read them via get_item_names.",
          "descriptionKey": "ui.agent.fileManager.state.items"
        },
        {
          "name": "activeAction",
          "type": "'none' | 'create-folder' | 'rename' | 'delete' | 'move'",
          "description": "The single in-flight action dialog. Only one action can be active at a time.",
          "descriptionKey": "ui.agent.fileManager.state.activeAction"
        }
      ],
      "actions": [
        {
          "name": "select_items",
          "safety": "read",
          "argsType": "{ ids: string[] }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "ids": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Item ids to select (replaces the current selection)."
              }
            },
            "required": [
              "ids"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "ids": [
                  "doc-1",
                  "doc-2"
                ]
              },
              "note": "Select two items."
            }
          ],
          "description": "Replace the current selection with the given item ids.",
          "descriptionKey": "ui.agent.fileManager.actions.selectItems"
        },
        {
          "name": "clear_selection",
          "safety": "read",
          "idempotent": true,
          "description": "Deselect every item.",
          "descriptionKey": "ui.agent.fileManager.actions.clearSelection"
        },
        {
          "name": "navigate",
          "safety": "read",
          "argsType": "{ folderId: string | null }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "folderId": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Folder id to open, or null for the root."
              }
            },
            "required": [
              "folderId"
            ]
          },
          "idempotent": true,
          "description": "Open the given folder (null for the root). Clears the current selection.",
          "descriptionKey": "ui.agent.fileManager.actions.navigate"
        },
        {
          "name": "set_type_filter",
          "safety": "read",
          "argsType": "{ documentTypes: string[] }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "documentTypes": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Document-type values to keep. Empty array clears the filter."
              }
            },
            "required": [
              "documentTypes"
            ]
          },
          "idempotent": true,
          "description": "Filter the open folder to the given document types (empty clears the filter).",
          "descriptionKey": "ui.agent.fileManager.actions.setTypeFilter"
        },
        {
          "name": "open_item",
          "safety": "read",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "Item id — folders navigate, files open via the host."
              }
            },
            "required": [
              "id"
            ]
          },
          "openWorld": true,
          "description": "Open an item: folders navigate into the folder, files resolve through the host preview callback.",
          "descriptionKey": "ui.agent.fileManager.actions.openItem"
        },
        {
          "name": "list_items",
          "safety": "read",
          "argsType": "{ folderId?: string | null }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "folderId": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Folder whose children to list (null = root). Omit for every item."
              }
            }
          },
          "returns": "Array<{ id, kind, parentId, size, updatedAt }>",
          "returnsSchema": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "kind": {
                  "enum": [
                    "file",
                    "folder"
                  ]
                },
                "parentId": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "Parent folder id, null at the root."
                },
                "size": {
                  "type": "number",
                  "description": "Bytes — files only."
                },
                "updatedAt": {
                  "type": "string",
                  "description": "ISO 8601 timestamp."
                },
                "documentType": {
                  "type": "string",
                  "description": "Document-type category (non-identifying)."
                },
                "signatureStatus": {
                  "enum": [
                    "none",
                    "pending",
                    "signed"
                  ],
                  "description": "Signature workflow state."
                }
              },
              "required": [
                "id",
                "kind",
                "parentId"
              ]
            }
          },
          "idempotent": true,
          "description": "List structural metadata (ids, kinds, sizes, dates — never names) for a folder or the whole tree.",
          "descriptionKey": "ui.agent.fileManager.actions.listItems"
        },
        {
          "name": "get_item_names",
          "safety": "phi",
          "argsType": "{ ids: string[] }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "ids": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Item ids whose display names to read."
              }
            },
            "required": [
              "ids"
            ]
          },
          "returns": "Array<{ id: string; name: string }>",
          "returnsSchema": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                }
              },
              "required": [
                "id",
                "name"
              ]
            }
          },
          "idempotent": true,
          "description": "Read the display names for the given item ids. Names may identify patients (PHI).",
          "descriptionKey": "ui.agent.fileManager.actions.getItemNames"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "file-manager",
          "description": "Marks the FileManager region."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        },
        "item": {
          "attr": "data-item-id",
          "description": "Grid cards and folder-tree nodes carry the item id as data-item-id (ids only — never names). List-view rows are AG Grid rows inside the composed DataTable and carry its native row-id attribute keyed to the same ids."
        }
      }
    },
    {
      "kind": "component",
      "id": "file-upload",
      "capabilities": [
        "dismiss"
      ],
      "state": [
        {
          "name": "files",
          "type": "Array<{ id, name, size, status }>",
          "description": "Files currently tracked by the uploader. Identifiers and metadata only — never file content.",
          "descriptionKey": "ui.agent.fileUpload.state.files"
        }
      ],
      "actions": [
        {
          "name": "remove_file",
          "safety": "destructive",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "Id of the tracked file to remove (data-file-id)."
              }
            },
            "required": [
              "id"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "id": "file-1"
              },
              "note": "Remove the first tracked file."
            }
          ],
          "description": "Remove the file with the given id from the upload list.",
          "descriptionKey": "ui.agent.fileUpload.actions.removeFile"
        },
        {
          "name": "clear",
          "safety": "destructive",
          "idempotent": true,
          "description": "Remove all files from the upload list.",
          "descriptionKey": "ui.agent.fileUpload.actions.clear"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "file-upload"
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        },
        "item": {
          "attr": "data-file-id",
          "description": "Each tracked file emits its id as data-file-id."
        }
      }
    },
    {
      "kind": "component",
      "id": "finished-terminal",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "finished-terminal",
          "description": "Marks the element as a kit FinishedTerminal."
        }
      }
    },
    {
      "kind": "component",
      "id": "fiscal-code-input",
      "capabilities": [
        "set_value"
      ],
      "state": [
        {
          "name": "value",
          "type": "string",
          "description": "Current codice fiscale, normalised (uppercased, 0–16 [A-Z0-9] characters).",
          "descriptionKey": "ui.agent.fiscalCodeInput.state.value"
        },
        {
          "name": "isValid",
          "type": "boolean",
          "description": "Whether the value is 16 structurally-sound characters with a matching control character.",
          "descriptionKey": "ui.agent.fiscalCodeInput.state.isValid"
        }
      ],
      "actions": [
        {
          "name": "set_value",
          "safety": "write",
          "argsType": "{ value: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "value": {
                "type": "string"
              }
            },
            "required": [
              "value"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "value": "RSSMRA85T10A562S"
              },
              "note": "A complete, structurally-sound codice fiscale."
            }
          ],
          "description": "Replace the codice fiscale. The value is uppercased and stripped to [A-Z0-9], capped at 16 characters.",
          "descriptionKey": "ui.agent.fiscalCodeInput.actions.setValue"
        },
        {
          "name": "clear",
          "safety": "destructive",
          "idempotent": true,
          "description": "Empty the input. Loses any typed value.",
          "descriptionKey": "ui.agent.fiscalCodeInput.actions.clear"
        },
        {
          "name": "focus",
          "safety": "read",
          "description": "Move keyboard focus to the codice fiscale input.",
          "descriptionKey": "ui.agent.fiscalCodeInput.actions.focus"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "fiscal-code-input",
          "description": "Marks the FiscalCodeInput wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "flag",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "flag",
          "description": "Marks the element as a kit Flag glyph."
        }
      }
    },
    {
      "kind": "component",
      "id": "floating-action-button",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "floating-action-button",
          "description": "Marks the element as a kit FloatingActionButton. Safety is declared by the host pattern, not the button."
        }
      }
    },
    {
      "kind": "component",
      "id": "form-field",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "form-field",
          "description": "Marks the FormField wrapper. The label, description, and error are siblings of the inner input; agents address the input by its native `id`, which FormField wires up via context."
        }
      }
    },
    {
      "kind": "component",
      "id": "freemium-paywall",
      "capabilities": [
        "submit",
        "dismiss"
      ],
      "state": [
        {
          "name": "isOpen",
          "type": "boolean",
          "description": "True when the paywall dialog is open.",
          "descriptionKey": "ui.agent.freemiumPaywall.state.isOpen"
        },
        {
          "name": "selectedPlanId",
          "type": "string | null",
          "description": "Opaque id of the currently-selected plan.",
          "descriptionKey": "ui.agent.freemiumPaywall.state.selectedPlanId"
        }
      ],
      "actions": [
        {
          "name": "upgrade",
          "safety": "write",
          "openWorld": true,
          "errors": [
            "No plan selected — upgrade is a no-op until a plan is chosen."
          ],
          "description": "Fire onUpgrade with the currently-selected plan id.",
          "descriptionKey": "ui.agent.freemiumPaywall.actions.upgrade"
        },
        {
          "name": "dismiss",
          "safety": "destructive",
          "description": "Dismiss the paywall via the Not Now action. Irreversible from the same UI.",
          "descriptionKey": "ui.agent.freemiumPaywall.actions.dismiss"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "freemium-paywall",
          "description": "Marks the FreemiumPaywall dialog content."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "gestational-age-calculator",
      "capabilities": [
        "set_value"
      ],
      "state": [
        {
          "name": "inputs",
          "type": "{ method: 'lmp' | 'edd', referenceDate: string | null, asOfDate: string }",
          "description": "The dating inputs as entered — whether the reference date is a last period or a known due date, that date, and the evaluation date. Dates are `yyyy-MM-dd`. Read this to see which method a reference date will be interpreted under.",
          "descriptionKey": "ui.agent.gestationalAgeCalculator.state.inputs"
        },
        {
          "name": "result",
          "type": "{ gestationalAge: { weeks: number, days: number, totalDays: number } | null, trimester: string, dueDate: string } | null",
          "description": "Computed gestational age in completed weeks + days as of the evaluation date, the trimester band (preconception / first / second / third / postterm), and the estimated delivery date. Null until a reference date is set.",
          "descriptionKey": "ui.agent.gestationalAgeCalculator.state.result"
        }
      ],
      "actions": [
        {
          "name": "set_method",
          "safety": "write",
          "argsType": "{ method: 'lmp' | 'edd' }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "method": {
                "enum": [
                  "lmp",
                  "edd"
                ],
                "description": "Whether the reference date is the last menstrual period or a known estimated delivery date."
              }
            },
            "required": [
              "method"
            ],
            "additionalProperties": false
          },
          "returns": "boolean",
          "returnsSchema": {
            "type": "boolean",
            "description": "True when the method was applied."
          },
          "idempotent": true,
          "errors": [
            "Returns false for a method other than `lmp` or `edd`."
          ],
          "deprecated": "Superseded by the `pregnancy-dating` adapter.",
          "description": "Choose how the reference date is read. The date is kept and re-interpreted under the new method, so set the method first — an EDD may be in the future, an LMP may not.",
          "descriptionKey": "ui.agent.gestationalAgeCalculator.actions.setMethod"
        },
        {
          "name": "set_reference_date",
          "safety": "write",
          "argsType": "{ date: string | null }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "date": {
                "oneOf": [
                  {
                    "type": "string",
                    "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                    "description": "Local calendar date, `yyyy-MM-dd`."
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "The last period (not in the future) or the known due date, depending on the active method — or null to clear it."
              }
            },
            "required": [
              "date"
            ],
            "additionalProperties": false
          },
          "returns": "boolean",
          "returnsSchema": {
            "type": "boolean",
            "description": "True when the date was applied."
          },
          "idempotent": true,
          "errors": [
            "Returns false for an unparseable date, or for a future date under the `lmp` method — the on-screen DatePicker caps an LMP at today."
          ],
          "examples": [
            {
              "args": {
                "date": "2026-01-12"
              },
              "note": "Under the default LMP method, a last period starting 12 January."
            }
          ],
          "deprecated": "Superseded by the `pregnancy-dating` adapter.",
          "description": "Set the dating anchor. This is the only required input — the result stays null without it.",
          "descriptionKey": "ui.agent.gestationalAgeCalculator.actions.setReferenceDate"
        },
        {
          "name": "set_as_of_date",
          "safety": "write",
          "argsType": "{ date: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "date": {
                "type": "string",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                "description": "Date to evaluate gestational age and trimester against, `yyyy-MM-dd`. May be in the future to project forward."
              }
            },
            "required": [
              "date"
            ],
            "additionalProperties": false
          },
          "returns": "boolean",
          "returnsSchema": {
            "type": "boolean",
            "description": "True when the date was applied."
          },
          "idempotent": true,
          "errors": [
            "Returns false for an unparseable date."
          ],
          "examples": [
            {
              "args": {
                "date": "2026-09-15"
              },
              "note": "Project gestational age forward to an upcoming appointment."
            }
          ],
          "deprecated": "Superseded by the `pregnancy-dating` adapter.",
          "description": "Set the date gestational age, trimester and the antenatal schedule are evaluated against. Defaults to today; the estimated delivery date itself does not depend on it.",
          "descriptionKey": "ui.agent.gestationalAgeCalculator.actions.setAsOfDate"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "gestational-age-calculator",
          "description": "Marks the GestationalAgeCalculator (current gestational age, trimester and milestones from LMP or due date)."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop. Also the registry key — without an `id` the instance does not register and the handle-driven actions/state are unreachable."
        }
      }
    },
    {
      "kind": "component",
      "id": "hcg-doubling",
      "capabilities": [
        "set_value"
      ],
      "state": [
        {
          "name": "samples",
          "type": "{ hcg1: number | null, date1: string | null, hcg2: number | null, date2: string | null }",
          "description": "The two timed β-hCG samples as entered — value in mIU/mL plus the draw time as an ISO-8601 timestamp. Null where unset. Read this to see why a result is still null.",
          "descriptionKey": "ui.agent.hcgDoubling.state.samples"
        },
        {
          "name": "result",
          "type": "{ intervalHours: number, ratio: number, percentRise: number, twoDayRisePercent: number, doublingTimeHours: number | null, trend: 'rising-normal' | 'rising-slow' | 'plateau-falling' } | null",
          "description": "Computed doubling time in hours (null when not rising), the rise normalised to 48 hours, and the trend band against the minimal-rise benchmark. Null until both samples are set and the second is after the first.",
          "descriptionKey": "ui.agent.hcgDoubling.state.result"
        }
      ],
      "actions": [
        {
          "name": "set_samples",
          "safety": "write",
          "argsType": "{ hcg1?: number | null, date1?: string | null, hcg2?: number | null, date2?: string | null }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "hcg1": {
                "oneOf": [
                  {
                    "type": "number",
                    "exclusiveMinimum": 0
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "First β-hCG value in mIU/mL, or null to clear it."
              },
              "date1": {
                "oneOf": [
                  {
                    "type": "string",
                    "format": "date-time"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "When the first sample was drawn as an ISO-8601 timestamp with offset (e.g. 2026-08-01T09:30:00+02:00), not in the future, or null to clear it."
              },
              "hcg2": {
                "oneOf": [
                  {
                    "type": "number",
                    "exclusiveMinimum": 0
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Second β-hCG value in mIU/mL, or null to clear it."
              },
              "date2": {
                "oneOf": [
                  {
                    "type": "string",
                    "format": "date-time"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "When the second sample was drawn as an ISO-8601 timestamp with offset (e.g. 2026-08-01T09:30:00+02:00), not in the future, or null to clear it."
              }
            },
            "additionalProperties": false
          },
          "returns": "boolean",
          "returnsSchema": {
            "type": "boolean",
            "description": "True when the samples were applied."
          },
          "idempotent": true,
          "errors": [
            "Returns false and writes nothing when a value is not positive, a timestamp is unparseable, or a timestamp is in the future — the payload applies all-or-nothing.",
            "Applies cleanly but leaves `result` null when the second sample is not strictly after the first — the analysis needs a forward interval."
          ],
          "examples": [
            {
              "args": {
                "hcg1": 1200,
                "date1": "2026-08-01T09:00:00+02:00",
                "hcg2": 2500,
                "date2": "2026-08-03T09:00:00+02:00"
              },
              "note": "A doubling over 48 hours → the rising-normal band."
            }
          ],
          "description": "Set any subset of the two timed β-hCG samples. Omitted keys are left unchanged; an explicit null clears one. All four are needed before a trend is computed.",
          "descriptionKey": "ui.agent.hcgDoubling.actions.setSamples"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "hcg-doubling",
          "description": "Marks the HcgDoubling calculator (serum β-hCG doubling time from two timed values)."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop. Also the registry key — without an `id` the instance does not register and the handle-driven action/state are unreachable."
        }
      }
    },
    {
      "kind": "component",
      "id": "header",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "header",
          "description": "Marks the page Header banner. Emits `data-scrolled=\"true\"` while the user has scrolled past the sentinel. Inner controls (HeaderBrand, HeaderMenuButton, etc.) carry their own component hooks."
        }
      }
    },
    {
      "kind": "component",
      "id": "header-settings",
      "capabilities": [
        "set_value"
      ],
      "state": [
        {
          "name": "locale",
          "type": "string",
          "description": "Active IETF language tag (e.g. \"en\", \"it\", \"ar\"). Initially uses HTML lang first when followHtmlLang is enabled; otherwise storage, then HTML lang when initialLocaleFromHtmlLang is enabled, then the browser. Read after set_locale to confirm the switch; unknown tags leave it unchanged.",
          "descriptionKey": "ui.agent.headerSettings.state.locale"
        },
        {
          "name": "theme",
          "type": "'light' | 'dark' | 'system'",
          "description": "Stored base-theme preference. `'system'` means no override is set and the OS decides — read `resolvedTheme` for what is actually painted.",
          "descriptionKey": "ui.agent.headerSettings.state.theme"
        },
        {
          "name": "accessibility",
          "type": "'default' | 'accessible' | 'system'",
          "description": "Stored AAA-contrast preference. `'system'` means no override is set and `prefers-contrast` decides.",
          "descriptionKey": "ui.agent.headerSettings.state.accessibility"
        },
        {
          "name": "resolvedTheme",
          "type": "'light' | 'dark' | 'light-accessible' | 'dark-accessible'",
          "description": "The theme actually applied to the document once preference and OS signals resolve. This is what makes a `set_theme(\"system\")` or `set_accessibility(\"system\")` write verifiable.",
          "descriptionKey": "ui.agent.headerSettings.state.resolvedTheme"
        }
      ],
      "actions": [
        {
          "name": "set_locale",
          "safety": "write",
          "argsType": "{ locale: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "locale": {
                "type": "string",
                "description": "IETF language tag (e.g. \"en\", \"it\", \"ar\"). Unknown tags are silently dropped."
              }
            },
            "required": [
              "locale"
            ]
          },
          "idempotent": true,
          "errors": [
            "Silently ignored when the tag names a locale the kit ships no bundle for — `locale` is unchanged."
          ],
          "examples": [
            {
              "args": {
                "locale": "it"
              },
              "note": "Switch to Italian."
            }
          ],
          "description": "Switch the active locale to the given IETF tag. Unknown tags are silently dropped — read the `locale` state slot afterwards to confirm. On a site with one address per language, the host may then load that language's address.",
          "descriptionKey": "ui.agent.headerSettings.actions.setLocale"
        },
        {
          "name": "set_theme",
          "safety": "write",
          "argsType": "{ theme: \"light\" | \"dark\" | \"system\" }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "theme": {
                "enum": [
                  "light",
                  "dark",
                  "system"
                ]
              }
            },
            "required": [
              "theme"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "theme": "dark"
              },
              "note": "Switch to the dark theme."
            }
          ],
          "description": "Switch the theme preference. Verify with the `theme` slot (the stored preference) and `resolvedTheme` (what is actually painted).",
          "descriptionKey": "ui.agent.headerSettings.actions.setTheme"
        },
        {
          "name": "set_accessibility",
          "safety": "write",
          "argsType": "{ accessibility: \"default\" | \"accessible\" | \"system\" }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "accessibility": {
                "enum": [
                  "default",
                  "accessible",
                  "system"
                ],
                "description": "`'system'` clears the override and follows `prefers-contrast`."
              }
            },
            "required": [
              "accessibility"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "accessibility": "accessible"
              },
              "note": "Enable the AAA-accessible profile."
            }
          ],
          "description": "Switch the accessibility preference. Verify with the `accessibility` slot (the stored preference) and `resolvedTheme` (what is actually painted).",
          "descriptionKey": "ui.agent.headerSettings.actions.setAccessibility"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "header-settings",
          "description": "Marks the HeaderSettings wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop (forwarded via HTMLAttributes)."
        }
      }
    },
    {
      "kind": "component",
      "id": "heatmap",
      "capabilities": [
        "select_single",
        "select_multiple",
        "range_pick",
        "expand",
        "sort",
        "view_change"
      ],
      "state": [
        {
          "name": "selection",
          "type": "Array<{ rowId, columnId }>",
          "description": "Row and column ids of the selected cells.",
          "descriptionKey": "ui.agent.heatmap.state.selection"
        },
        {
          "name": "selectionMode",
          "type": "'none' | 'single' | 'multiple' | 'range'",
          "description": "How cells can be selected in this heatmap.",
          "descriptionKey": "ui.agent.heatmap.state.selectionMode"
        },
        {
          "name": "view",
          "type": "'heatmap' | 'table'",
          "description": "Whether the heatmap or its table view is showing.",
          "descriptionKey": "ui.agent.heatmap.state.view"
        },
        {
          "name": "sortRows",
          "type": "'none' | 'label' | 'total-asc' | 'total-desc'",
          "description": "Current row order.",
          "descriptionKey": "ui.agent.heatmap.state.sortRows"
        },
        {
          "name": "rowIds",
          "type": "string[]",
          "description": "Row ids in display order, every group expanded. Opaque, never a label.",
          "descriptionKey": "ui.agent.heatmap.state.rowIds"
        },
        {
          "name": "columnIds",
          "type": "Array<string | number>",
          "description": "Column ids in order. Opaque, never a label.",
          "descriptionKey": "ui.agent.heatmap.state.columnIds"
        },
        {
          "name": "groupIds",
          "type": "string[]",
          "description": "Group ids in display order, empty unless rows are grouped. A group not listed in `groups` shows as group-1, group-2 and so on.",
          "descriptionKey": "ui.agent.heatmap.state.groupIds"
        },
        {
          "name": "collapsedGroups",
          "type": "string[]",
          "description": "Ids (as in groupIds) of the row groups that are collapsed.",
          "descriptionKey": "ui.agent.heatmap.state.collapsedGroups"
        }
      ],
      "actions": [
        {
          "name": "select_cell",
          "safety": "read",
          "argsType": "{ rowId: string, columnId: string | number }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "rowId": {
                "type": "string",
                "description": "Row id, from rowIds."
              },
              "columnId": {
                "type": [
                  "string",
                  "number"
                ],
                "description": "Column id, from columnIds."
              }
            },
            "required": [
              "rowId",
              "columnId"
            ]
          },
          "idempotent": true,
          "errors": [
            "Selection is off (selection=\"none\").",
            "The row or column id does not exist."
          ],
          "examples": [
            {
              "args": {
                "rowId": "chair-1",
                "columnId": 10
              },
              "note": "Select chair 1 at 10:00."
            }
          ],
          "description": "Make one cell the whole selection.",
          "descriptionKey": "ui.agent.heatmap.actions.selectCell"
        },
        {
          "name": "select_cells",
          "safety": "read",
          "argsType": "{ cells: Array<{ rowId, columnId }> }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "cells": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "rowId": {
                      "type": "string",
                      "description": "Row id, from rowIds."
                    },
                    "columnId": {
                      "type": [
                        "string",
                        "number"
                      ],
                      "description": "Column id, from columnIds."
                    }
                  },
                  "required": [
                    "rowId",
                    "columnId"
                  ]
                },
                "description": "Cells to select; replaces the selection. Single mode keeps the first."
              }
            },
            "required": [
              "cells"
            ]
          },
          "idempotent": true,
          "errors": [
            "Selection is off (selection=\"none\").",
            "A row or column id does not exist; nothing is selected."
          ],
          "description": "Replace the selection with the given cells.",
          "descriptionKey": "ui.agent.heatmap.actions.selectCells"
        },
        {
          "name": "select_range",
          "safety": "read",
          "argsType": "{ from: { rowId, columnId }, to: { rowId, columnId } }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "from": {
                "type": "object",
                "properties": {
                  "rowId": {
                    "type": "string",
                    "description": "Row id, from rowIds."
                  },
                  "columnId": {
                    "type": [
                      "string",
                      "number"
                    ],
                    "description": "Column id, from columnIds."
                  }
                },
                "required": [
                  "rowId",
                  "columnId"
                ],
                "description": "One corner, inclusive."
              },
              "to": {
                "type": "object",
                "properties": {
                  "rowId": {
                    "type": "string",
                    "description": "Row id, from rowIds."
                  },
                  "columnId": {
                    "type": [
                      "string",
                      "number"
                    ],
                    "description": "Column id, from columnIds."
                  }
                },
                "required": [
                  "rowId",
                  "columnId"
                ],
                "description": "The opposite corner, inclusive."
              }
            },
            "required": [
              "from",
              "to"
            ]
          },
          "idempotent": true,
          "errors": [
            "Needs selection=\"range\" or \"multiple\".",
            "A corner names a row or column that does not exist."
          ],
          "description": "Select the rectangle of cells between two corners, in the rows as shown.",
          "descriptionKey": "ui.agent.heatmap.actions.selectRange"
        },
        {
          "name": "clear_selection",
          "safety": "read",
          "idempotent": true,
          "errors": [
            "Selection is off (selection=\"none\")."
          ],
          "description": "Deselect every cell.",
          "descriptionKey": "ui.agent.heatmap.actions.clearSelection"
        },
        {
          "name": "read_cell",
          "safety": "read",
          "argsType": "{ rowId: string, columnId: string | number }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "rowId": {
                "type": "string",
                "description": "Row id, from rowIds."
              },
              "columnId": {
                "type": [
                  "string",
                  "number"
                ],
                "description": "Column id, from columnIds."
              }
            },
            "required": [
              "rowId",
              "columnId"
            ]
          },
          "returns": "{ value, count, status, step } | null",
          "returnsSchema": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "value": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "count": {
                "type": "number"
              },
              "status": {
                "enum": [
                  "value",
                  "empty",
                  "low-sample"
                ]
              },
              "step": {
                "type": [
                  "number",
                  "null"
                ]
              }
            }
          },
          "idempotent": true,
          "description": "Read a cell's value, count, status and colour step (no labels).",
          "descriptionKey": "ui.agent.heatmap.actions.readCell"
        },
        {
          "name": "toggle_table_view",
          "safety": "read",
          "returns": "'heatmap' | 'table'",
          "returnsSchema": {
            "enum": [
              "heatmap",
              "table"
            ]
          },
          "description": "Switch between the heatmap and its table view.",
          "descriptionKey": "ui.agent.heatmap.actions.toggleTableView"
        },
        {
          "name": "set_view",
          "safety": "read",
          "argsType": "{ view: 'heatmap' | 'table' }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "view": {
                "enum": [
                  "heatmap",
                  "table"
                ],
                "description": "The coloured grid, or the same data as a table."
              }
            },
            "required": [
              "view"
            ]
          },
          "idempotent": true,
          "description": "Show the heatmap or its table view.",
          "descriptionKey": "ui.agent.heatmap.actions.setView"
        },
        {
          "name": "sort_rows",
          "safety": "read",
          "argsType": "{ sort: 'none' | 'label' | 'total-asc' | 'total-desc' }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "sort": {
                "enum": [
                  "none",
                  "label",
                  "total-asc",
                  "total-desc"
                ],
                "description": "Row order within each group: as given, by label, or by row total."
              }
            },
            "required": [
              "sort"
            ]
          },
          "idempotent": true,
          "description": "Reorder the rows.",
          "descriptionKey": "ui.agent.heatmap.actions.sortRows"
        },
        {
          "name": "expand_group",
          "safety": "read",
          "argsType": "{ groupId: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "groupId": {
                "type": "string",
                "description": "Group id, from groupIds."
              }
            },
            "required": [
              "groupId"
            ]
          },
          "idempotent": true,
          "errors": [
            "Rows are not grouped (groupRows is off).",
            "The group id does not exist (see groupIds)."
          ],
          "description": "Show a group's rows.",
          "descriptionKey": "ui.agent.heatmap.actions.expandGroup"
        },
        {
          "name": "collapse_group",
          "safety": "read",
          "argsType": "{ groupId: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "groupId": {
                "type": "string",
                "description": "Group id, from groupIds."
              }
            },
            "required": [
              "groupId"
            ]
          },
          "idempotent": true,
          "errors": [
            "Rows are not grouped (groupRows is off).",
            "The group id does not exist (see groupIds)."
          ],
          "description": "Hide a group's rows, leaving its totals row.",
          "descriptionKey": "ui.agent.heatmap.actions.collapseGroup"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "heatmap",
          "description": "Marks the Heatmap root."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop on Heatmap."
        },
        "item": {
          "attr": "data-heatmap-cell-id",
          "description": "On every data cell: \"<rowId>:<columnId>\", built from the opaque ids, never from labels. A group header row and its cells carry data-heatmap-group-id, the group id as in groupIds."
        }
      }
    },
    {
      "kind": "component",
      "id": "hover-card",
      "capabilities": [
        "open",
        "close"
      ],
      "state": [
        {
          "name": "isOpen",
          "type": "boolean",
          "description": "True when the hover card is currently open.",
          "descriptionKey": "ui.agent.hoverCard.state.isOpen"
        }
      ],
      "actions": [
        {
          "name": "open",
          "safety": "read",
          "idempotent": true,
          "description": "Open the hover card without moving focus into it.",
          "descriptionKey": "ui.agent.hoverCard.actions.open"
        },
        {
          "name": "close",
          "safety": "read",
          "idempotent": true,
          "description": "Close the hover card.",
          "descriptionKey": "ui.agent.hoverCard.actions.close"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "hover-card"
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop on HoverCard.Root."
        }
      }
    },
    {
      "kind": "component",
      "id": "iban-input",
      "capabilities": [
        "set_value"
      ],
      "state": [
        {
          "name": "value",
          "type": "string",
          "description": "Current IBAN, normalised (uppercased, [A-Z0-9], no spaces, ≤34 characters).",
          "descriptionKey": "ui.agent.ibanInput.state.value"
        },
        {
          "name": "isValid",
          "type": "boolean",
          "description": "Whether the value is a structurally complete IBAN with a passing mod-97-10 checksum.",
          "descriptionKey": "ui.agent.ibanInput.state.isValid"
        }
      ],
      "actions": [
        {
          "name": "set_value",
          "safety": "write",
          "argsType": "{ value: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "value": {
                "type": "string"
              }
            },
            "required": [
              "value"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "value": "DE89370400440532013000"
              },
              "note": "A complete, checksum-valid German IBAN."
            }
          ],
          "description": "Replace the IBAN. The value is uppercased and stripped to [A-Z0-9], capped at 34 characters.",
          "descriptionKey": "ui.agent.ibanInput.actions.setValue"
        },
        {
          "name": "clear",
          "safety": "destructive",
          "idempotent": true,
          "description": "Empty the input. Loses any typed value.",
          "descriptionKey": "ui.agent.ibanInput.actions.clear"
        },
        {
          "name": "focus",
          "safety": "read",
          "description": "Move keyboard focus to the IBAN input.",
          "descriptionKey": "ui.agent.ibanInput.actions.focus"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "iban-input",
          "description": "Marks the IbanInput wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "icon-button",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "icon-button",
          "description": "Marks the element as a kit IconButton. Safety is declared by the host pattern, not the button. IconButtons inherit native `id` from props, which is what agents address them by."
        }
      }
    },
    {
      "kind": "component",
      "id": "icon-button-group",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "icon-button-group",
          "description": "Marks the IconButtonGroup wrapper. Agents target individual IconButtons inside the group via their native `id`."
        }
      }
    },
    {
      "kind": "component",
      "id": "icon-picker",
      "capabilities": [
        "pick",
        "filter",
        "open",
        "close"
      ],
      "state": [
        {
          "name": "value",
          "type": "string",
          "description": "Id of the currently selected icon, or an empty string when nothing is picked.",
          "descriptionKey": "ui.agent.iconPicker.state.value"
        },
        {
          "name": "isOpen",
          "type": "boolean",
          "description": "True when the picker popover is currently open.",
          "descriptionKey": "ui.agent.iconPicker.state.isOpen"
        },
        {
          "name": "query",
          "type": "string",
          "description": "Current search query filtering the icon grid by label.",
          "descriptionKey": "ui.agent.iconPicker.state.query"
        }
      ],
      "actions": [
        {
          "name": "set_value",
          "safety": "write",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "Id of an icon in the supplied `icons` set."
              }
            },
            "required": [
              "id"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "id": "star"
              },
              "note": "Pick the \"star\" icon."
            }
          ],
          "description": "Select the icon with the given id.",
          "descriptionKey": "ui.agent.iconPicker.actions.setValue"
        },
        {
          "name": "open",
          "safety": "read",
          "idempotent": true,
          "description": "Open the picker popover.",
          "descriptionKey": "ui.agent.iconPicker.actions.open"
        },
        {
          "name": "close",
          "safety": "read",
          "idempotent": true,
          "description": "Close the picker popover.",
          "descriptionKey": "ui.agent.iconPicker.actions.close"
        },
        {
          "name": "filter",
          "safety": "write",
          "argsType": "{ query: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "query": {
                "type": "string",
                "description": "Case-insensitive substring matched against icon labels."
              }
            },
            "required": [
              "query"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "query": "star"
              },
              "note": "Show icons whose label contains \"star\"."
            }
          ],
          "description": "Filter the icon grid to labels containing the query.",
          "descriptionKey": "ui.agent.iconPicker.actions.filter"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "icon-picker",
          "description": "Marks the IconPicker trigger button."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "image-cropper",
      "capabilities": [
        "range_pick"
      ],
      "state": [
        {
          "name": "crop",
          "type": "object",
          "description": "Current crop rectangle in normalised [0,1] coordinates: { x, y, width, height }.",
          "descriptionKey": "ui.agent.imageCropper.state.crop"
        }
      ],
      "actions": [
        {
          "name": "set_crop",
          "safety": "write",
          "argsType": "{ x: number; y: number; width: number; height: number }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "x": {
                "type": "number",
                "minimum": 0,
                "maximum": 1
              },
              "y": {
                "type": "number",
                "minimum": 0,
                "maximum": 1
              },
              "width": {
                "type": "number",
                "minimum": 0,
                "maximum": 1
              },
              "height": {
                "type": "number",
                "minimum": 0,
                "maximum": 1
              }
            },
            "required": [
              "x",
              "y",
              "width",
              "height"
            ]
          },
          "idempotent": true,
          "description": "Set the crop rectangle (normalised [0,1]). Values are clamped to the image bounds and the minimum crop size.",
          "descriptionKey": "ui.agent.imageCropper.actions.setCrop"
        },
        {
          "name": "reset",
          "safety": "write",
          "idempotent": true,
          "description": "Reset the crop to the centred default for the current aspect.",
          "descriptionKey": "ui.agent.imageCropper.actions.reset"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "image-cropper",
          "description": "Marks the ImageCropper wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "info-tip",
      "capabilities": [
        "open",
        "close"
      ],
      "state": [
        {
          "name": "isOpen",
          "type": "boolean",
          "description": "True when the info tip card is currently open.",
          "descriptionKey": "ui.agent.infoTip.state.isOpen"
        }
      ],
      "actions": [
        {
          "name": "open",
          "safety": "read",
          "idempotent": true,
          "description": "Open the info tip card (including its formula and Learn more link, when set).",
          "descriptionKey": "ui.agent.infoTip.actions.open"
        },
        {
          "name": "close",
          "safety": "read",
          "idempotent": true,
          "description": "Close the info tip card.",
          "descriptionKey": "ui.agent.infoTip.actions.close"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "info-tip",
          "description": "Marks the InfoTip trigger button."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop on InfoTip."
        }
      }
    },
    {
      "kind": "component",
      "id": "kbd",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "kbd",
          "description": "Marks the element as a kit Kbd glyph."
        }
      }
    },
    {
      "kind": "component",
      "id": "key-value-pair",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "key-value-pair",
          "description": "Marks the element as a kit KeyValuePair row."
        }
      }
    },
    {
      "kind": "component",
      "id": "link",
      "capabilities": [
        "navigate"
      ],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "link",
          "description": "Marks the element as a kit Link. The destination URL is the native `href` attribute on the anchor; agents read it directly from the DOM. Also carries `data-variant` (`default` or `social`) and, for recognised social links, `data-social-network` (for example `instagram`); both are structural, with no patient data."
        }
      }
    },
    {
      "kind": "component",
      "id": "list",
      "capabilities": [
        "select_single",
        "select_multiple"
      ],
      "state": [
        {
          "name": "selection",
          "type": "string[]",
          "description": "Ids of currently-selected list items. Empty array when none selected or list is presentational.",
          "descriptionKey": "ui.agent.list.state.selection"
        }
      ],
      "actions": [
        {
          "name": "set_selection",
          "safety": "read",
          "argsType": "{ ids: string[] }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "ids": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Opaque item ids to select (from each ListItem `value`)."
              }
            },
            "required": [
              "ids"
            ]
          },
          "idempotent": true,
          "description": "Replace the current selection with the given item ids. No-op on presentational lists.",
          "descriptionKey": "ui.agent.list.actions.setSelection"
        },
        {
          "name": "clear_selection",
          "safety": "read",
          "idempotent": true,
          "description": "Deselect all items.",
          "descriptionKey": "ui.agent.list.actions.clearSelection"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "list",
          "description": "Marks the List root."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        },
        "item": {
          "attr": "data-item-id",
          "description": "Opaque item id; sourced from each ListItem `value` prop. Emitted only when `value` is set."
        }
      }
    },
    {
      "kind": "component",
      "id": "live-region",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "live-region",
          "description": "Marks the LiveRegion element. `aria-live` politeness and `role` are emitted as native attributes; announcement content is the element's text content."
        }
      }
    },
    {
      "kind": "component",
      "id": "locale-picker",
      "capabilities": [
        "set_value"
      ],
      "state": [
        {
          "name": "locale",
          "type": "string",
          "description": "Resolved IETF tag of the locale currently applied to the page. Read this after `set_locale` — the setter silently drops tags the kit ships no bundle for, so this is the only confirmation the switch landed.",
          "descriptionKey": "ui.agent.localePicker.state.locale"
        },
        {
          "name": "isSystemDefault",
          "type": "boolean",
          "description": "True when following navigator.language. False for a saved or explicit choice, or when initialLocaleFromHtmlLang or followHtmlLang used the page language. Read alongside locale to distinguish browser detection from a concrete language selection.",
          "descriptionKey": "ui.agent.localePicker.state.isSystemDefault"
        }
      ],
      "actions": [
        {
          "name": "set_locale",
          "safety": "write",
          "argsType": "{ locale: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "locale": {
                "type": "string",
                "description": "IETF language tag (e.g. \"en\", \"it\"). Unsupported tags are a no-op."
              }
            },
            "required": [
              "locale"
            ]
          },
          "idempotent": true,
          "errors": [
            "Silently ignored when the tag names a locale the kit ships no bundle for — `locale` is unchanged."
          ],
          "description": "Switch the active locale to the given IETF tag. Unsupported tags are a silent no-op — read the `locale` state slot afterwards to confirm the switch landed.",
          "descriptionKey": "ui.agent.localePicker.actions.setLocale"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "locale-picker",
          "description": "Marks the LocalePicker wrapper."
        }
      }
    },
    {
      "kind": "component",
      "id": "logo",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "logo",
          "description": "Marks the element as the AlfaDocs Logo asset."
        }
      }
    },
    {
      "kind": "component",
      "id": "map-view",
      "capabilities": [
        "scroll",
        "set_value",
        "pick"
      ],
      "state": [
        {
          "name": "consentGranted",
          "type": "boolean",
          "description": "True when the GDPR consent gate has been passed. Read this FIRST: while it is false every action is a silent no-op against a placeholder, and nothing else in the surface says so. When it is true but `center` is still null, Google Maps is loading; wait for `center` before acting.",
          "descriptionKey": "ui.agent.mapView.state.consentGranted"
        },
        {
          "name": "markerCount",
          "type": "number",
          "description": "Number of markers the consumer passed. Zero means there is nothing for `select_marker` to select. A count only — no ids, labels or positions.",
          "descriptionKey": "ui.agent.mapView.state.markerCount"
        },
        {
          "name": "selectedMarkerId",
          "type": "string | null",
          "description": "Id of the marker the host currently holds as selected, or null. Selection is fully controlled by the consumer, so `select_marker` only proposes — this slot is the only way to see whether the proposal was accepted.",
          "descriptionKey": "ui.agent.mapView.state.selectedMarkerId"
        },
        {
          "name": "center",
          "type": "{ lat: number; lng: number } | null",
          "description": "Live map centre in lat/lng, or null until the map has loaded (consent not granted, or Google Maps still loading). The read-back for `pan_to`, and the sign that the map is ready.",
          "descriptionKey": "ui.agent.mapView.state.center"
        },
        {
          "name": "zoom",
          "type": "number | null",
          "description": "Live zoom level, or null until the map has loaded. Google clamps zoom to the map type's range, so this is not necessarily the value last passed to `set_zoom`.",
          "descriptionKey": "ui.agent.mapView.state.zoom"
        }
      ],
      "actions": [
        {
          "name": "pan_to",
          "safety": "read",
          "argsType": "{ position: { lat: number; lng: number } }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "position": {
                "type": "object",
                "properties": {
                  "lat": {
                    "type": "number",
                    "description": "Latitude in degrees."
                  },
                  "lng": {
                    "type": "number",
                    "description": "Longitude in degrees."
                  }
                },
                "required": [
                  "lat",
                  "lng"
                ]
              }
            },
            "required": [
              "position"
            ]
          },
          "idempotent": true,
          "errors": [
            "Silent no-op until the map has loaded: while `consentGranted` is false (only the consent placeholder shows) or while `center` is still null (Google Maps is loading)."
          ],
          "description": "Pan the map to a new centre without changing zoom. Read the `center` slot back to confirm — Google animates the pan, so the applied centre settles after the call.",
          "descriptionKey": "ui.agent.mapView.actions.panTo"
        },
        {
          "name": "set_zoom",
          "safety": "read",
          "argsType": "{ zoom: number }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "zoom": {
                "type": "number",
                "description": "Zoom level, typical range 1–20."
              }
            },
            "required": [
              "zoom"
            ]
          },
          "idempotent": true,
          "errors": [
            "Silent no-op until the map has loaded: while `consentGranted` is false (only the consent placeholder shows) or while `center` is still null (Google Maps is loading).",
            "Requested zoom is clamped to the map type's range; `zoom` reports what was actually applied."
          ],
          "description": "Set the map zoom level (typical range 1–20). Read the `zoom` slot back — Google clamps the request to the map type’s supported range, so requested and applied can differ.",
          "descriptionKey": "ui.agent.mapView.actions.setZoom"
        },
        {
          "name": "select_marker",
          "safety": "read",
          "argsType": "{ id: string | null }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Marker id to select, or null to clear the selection."
              }
            },
            "required": [
              "id"
            ]
          },
          "idempotent": true,
          "errors": [
            "Silent no-op until the map has loaded: while `consentGranted` is false (only the consent placeholder shows) or while `center` is still null (Google Maps is loading).",
            "The host owns `selectedMarkerId` and may ignore the proposal; `selectedMarkerId` is unchanged when it does."
          ],
          "description": "Propose a marker selection by id, or pass null to clear it. Fires the host's `onMarkerClick`; selection is controlled by the host, so read the `selectedMarkerId` slot back to see whether it accepted.",
          "descriptionKey": "ui.agent.mapView.actions.selectMarker"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "map-view",
          "description": "Marks the element as a kit MapView."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "matrix-rain",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "matrix-rain",
          "description": "Marks the decorative MatrixRain canvas."
        }
      }
    },
    {
      "kind": "component",
      "id": "message-card",
      "capabilities": [
        "dismiss"
      ],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "message-card",
          "description": "Marks the element as a kit MessageCard. The card root also emits data-component-id sourced from item.id and data-read with the current read flag."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "item.id",
          "description": "Sourced from item.id — the stable message identifier."
        }
      }
    },
    {
      "kind": "component",
      "id": "message-tray",
      "capabilities": [
        "open",
        "close",
        "select_single",
        "dismiss",
        "navigate"
      ],
      "state": [
        {
          "name": "items",
          "type": "Array<{ id: string; read: boolean }>",
          "description": "Currently-displayed messages. Ids + read flag only — no PHI / no sender names.",
          "descriptionKey": "ui.agent.messageTray.state.items"
        },
        {
          "name": "unreadCount",
          "type": "number",
          "description": "Badge unread count surfaced by the host.",
          "descriptionKey": "ui.agent.messageTray.state.unreadCount"
        },
        {
          "name": "isOpen",
          "type": "boolean",
          "description": "Whether the dropdown panel is currently open.",
          "descriptionKey": "ui.agent.messageTray.state.isOpen"
        }
      ],
      "actions": [
        {
          "name": "open",
          "safety": "read",
          "idempotent": true,
          "description": "Open the message panel.",
          "descriptionKey": "ui.agent.messageTray.actions.open"
        },
        {
          "name": "close",
          "safety": "read",
          "idempotent": true,
          "description": "Close the message panel.",
          "descriptionKey": "ui.agent.messageTray.actions.close"
        },
        {
          "name": "select_item",
          "safety": "read",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "Stable message id to activate (sourced from item.id)."
              }
            },
            "required": [
              "id"
            ]
          },
          "examples": [
            {
              "args": {
                "id": "msg-1"
              },
              "note": "Open the message with id \"msg-1\"."
            }
          ],
          "description": "Activate the message with the given id.",
          "descriptionKey": "ui.agent.messageTray.actions.selectItem"
        },
        {
          "name": "mark_read",
          "safety": "write",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "Stable message id to mark as read."
              }
            },
            "required": [
              "id"
            ]
          },
          "idempotent": true,
          "description": "Request the host to mark a message as read.",
          "descriptionKey": "ui.agent.messageTray.actions.markRead"
        },
        {
          "name": "dismiss",
          "safety": "destructive",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "Stable message id to dismiss / archive."
              }
            },
            "required": [
              "id"
            ]
          },
          "idempotent": true,
          "description": "Request the host to dismiss / archive the message with the given id.",
          "descriptionKey": "ui.agent.messageTray.actions.dismiss"
        },
        {
          "name": "mark_all_read",
          "safety": "write",
          "idempotent": true,
          "description": "Request the host to mark every message as read.",
          "descriptionKey": "ui.agent.messageTray.actions.markAllRead"
        },
        {
          "name": "view_all",
          "safety": "read",
          "idempotent": true,
          "description": "Navigate to the full inbox / message list.",
          "descriptionKey": "ui.agent.messageTray.actions.viewAll"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "message-tray",
          "description": "Marks the MessageTray wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop. Required to address a specific tray from the agent."
        },
        "item": {
          "attr": "data-message-id",
          "description": "Stable message id emitted on each rendered MessageCard inside the tray."
        }
      }
    },
    {
      "kind": "component",
      "id": "money",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "money",
          "description": "Marks the element as a kit Money amount."
        }
      }
    },
    {
      "kind": "component",
      "id": "multi-select",
      "capabilities": [
        "select_multiple",
        "filter",
        "open",
        "close"
      ],
      "state": [
        {
          "name": "selection",
          "type": "string[]",
          "description": "Values of currently-selected options.",
          "descriptionKey": "ui.agent.multiSelect.state.selection"
        },
        {
          "name": "query",
          "type": "string",
          "description": "Current filter query.",
          "descriptionKey": "ui.agent.multiSelect.state.query"
        },
        {
          "name": "isOpen",
          "type": "boolean",
          "description": "True when the option list is visible.",
          "descriptionKey": "ui.agent.multiSelect.state.isOpen"
        }
      ],
      "actions": [
        {
          "name": "set_selection",
          "safety": "write",
          "argsType": "{ values: string[] }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "values": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Option values to select (replaces the current selection)."
              }
            },
            "required": [
              "values"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "values": [
                  "a",
                  "b"
                ]
              },
              "note": "Select exactly options \"a\" and \"b\"."
            }
          ],
          "description": "Replace the current selection with the given list of values.",
          "descriptionKey": "ui.agent.multiSelect.actions.setSelection"
        },
        {
          "name": "clear_selection",
          "safety": "destructive",
          "idempotent": true,
          "description": "Clear the current selection.",
          "descriptionKey": "ui.agent.multiSelect.actions.clearSelection"
        },
        {
          "name": "apply_filter",
          "safety": "read",
          "argsType": "{ query: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "query": {
                "type": "string",
                "description": "Filter text for the list."
              }
            },
            "required": [
              "query"
            ]
          },
          "idempotent": true,
          "description": "Set the filter query for the option list.",
          "descriptionKey": "ui.agent.multiSelect.actions.applyFilter"
        },
        {
          "name": "open",
          "safety": "read",
          "idempotent": true,
          "description": "Open the option list.",
          "descriptionKey": "ui.agent.multiSelect.actions.open"
        },
        {
          "name": "close",
          "safety": "read",
          "idempotent": true,
          "description": "Close the option list.",
          "descriptionKey": "ui.agent.multiSelect.actions.close"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "multi-select"
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        },
        "item": {
          "attr": "data-option-id",
          "description": "Each option emits its value as data-option-id."
        }
      }
    },
    {
      "kind": "component",
      "id": "muscle-scheme",
      "capabilities": [
        "pick",
        "set_value",
        "edit_inline",
        "view_change"
      ],
      "state": [
        {
          "name": "chart",
          "type": "object",
          "description": "Current muscle chart — findings keyed by region id. Notes are PHI and omitted from this snapshot; read them per-region via get_region.",
          "descriptionKey": "ui.agent.muscleScheme.state.chart"
        },
        {
          "name": "activeView",
          "type": "string",
          "description": "Id of the currently displayed muscle view.",
          "descriptionKey": "ui.agent.muscleScheme.state.activeView"
        }
      ],
      "actions": [
        {
          "name": "focus_region",
          "safety": "read",
          "argsType": "{ regionId: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "regionId": {
                "type": "string",
                "description": "Per-muscle region id within the active view, e.g. 'quadriceps-r', 'biceps-l', 'pectoralis-r', 'trapezius-l'."
              }
            },
            "required": [
              "regionId"
            ]
          },
          "idempotent": true,
          "description": "Move focus to a specific region in the active view.",
          "descriptionKey": "ui.agent.muscleScheme.actions.focusRegion"
        },
        {
          "name": "get_region",
          "safety": "phi",
          "argsType": "{ regionId: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "regionId": {
                "type": "string",
                "description": "Per-muscle region id within the active view, e.g. 'quadriceps-r', 'biceps-l', 'pectoralis-r', 'trapezius-l'."
              }
            },
            "required": [
              "regionId"
            ]
          },
          "returns": "MuscleFinding[]",
          "returnsSchema": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "type": {
                  "enum": [
                    "observation",
                    "lesion",
                    "pain",
                    "treatment",
                    "note"
                  ]
                },
                "note": {
                  "type": "string"
                }
              },
              "required": [
                "type"
              ]
            }
          },
          "idempotent": true,
          "description": "Read the findings (incl. notes) recorded on one region.",
          "descriptionKey": "ui.agent.muscleScheme.actions.getRegion"
        },
        {
          "name": "regions_with",
          "safety": "read",
          "argsType": "{ type: FindingType }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "type": {
                "enum": [
                  "observation",
                  "lesion",
                  "pain",
                  "treatment",
                  "note"
                ]
              }
            },
            "required": [
              "type"
            ]
          },
          "returns": "string[]",
          "returnsSchema": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "Per-muscle region id within the active view, e.g. 'quadriceps-r', 'biceps-l', 'pectoralis-r', 'trapezius-l'."
            }
          },
          "idempotent": true,
          "description": "List the region ids carrying a given finding type.",
          "descriptionKey": "ui.agent.muscleScheme.actions.regionsWith"
        },
        {
          "name": "set_finding",
          "safety": "write",
          "argsType": "{ regionId: string; type: FindingType; note?: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "regionId": {
                "type": "string",
                "description": "Per-muscle region id within the active view, e.g. 'quadriceps-r', 'biceps-l', 'pectoralis-r', 'trapezius-l'."
              },
              "type": {
                "enum": [
                  "observation",
                  "lesion",
                  "pain",
                  "treatment",
                  "note"
                ]
              },
              "note": {
                "type": "string"
              }
            },
            "required": [
              "regionId",
              "type"
            ]
          },
          "idempotent": true,
          "description": "Record a finding (observation / lesion / pain / treatment / note) on a region.",
          "descriptionKey": "ui.agent.muscleScheme.actions.setFinding"
        },
        {
          "name": "remove_finding",
          "safety": "write",
          "argsType": "{ regionId: string; type: FindingType }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "regionId": {
                "type": "string",
                "description": "Per-muscle region id within the active view, e.g. 'quadriceps-r', 'biceps-l', 'pectoralis-r', 'trapezius-l'."
              },
              "type": {
                "enum": [
                  "observation",
                  "lesion",
                  "pain",
                  "treatment",
                  "note"
                ]
              }
            },
            "required": [
              "regionId",
              "type"
            ]
          },
          "idempotent": true,
          "description": "Remove a single finding type from a region.",
          "descriptionKey": "ui.agent.muscleScheme.actions.removeFinding"
        },
        {
          "name": "clear_region",
          "safety": "destructive",
          "argsType": "{ regionId: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "regionId": {
                "type": "string",
                "description": "Per-muscle region id within the active view, e.g. 'quadriceps-r', 'biceps-l', 'pectoralis-r', 'trapezius-l'."
              }
            },
            "required": [
              "regionId"
            ]
          },
          "idempotent": true,
          "description": "Clear every finding from a region.",
          "descriptionKey": "ui.agent.muscleScheme.actions.clearRegion"
        },
        {
          "name": "set_view",
          "safety": "write",
          "argsType": "{ viewId: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "viewId": {
                "type": "string",
                "description": "View id, e.g. 'muscular-front', 'muscular-back', 'muscular-front-female', 'muscular-back-female', 'muscular-front-child', 'muscular-back-child'."
              }
            },
            "required": [
              "viewId"
            ]
          },
          "idempotent": true,
          "description": "Switch the active muscle view.",
          "descriptionKey": "ui.agent.muscleScheme.actions.setView"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "muscle-scheme"
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        },
        "item": {
          "attr": "data-region",
          "description": "Each rendered region `<g>` carries its region id as `data-region` and its anatomical side (`left` / `right` / `midline`) as `data-side`, so bilateral regions can be disambiguated by side. The root `data-view` attribute exposes the active muscle view."
        }
      }
    },
    {
      "kind": "component",
      "id": "nav-grid",
      "capabilities": [
        "navigate"
      ],
      "state": [
        {
          "name": "itemCount",
          "type": "number",
          "description": "Number of navigable tiles currently rendered in the grid.",
          "descriptionKey": "ui.agent.navGrid.state.itemCount"
        }
      ],
      "actions": [
        {
          "name": "open_item",
          "safety": "write",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "Stable opaque tile id (emitted as data-nav-item-id on each tile)."
              }
            },
            "required": [
              "id"
            ]
          },
          "openWorld": false,
          "examples": [
            {
              "args": {
                "id": "billing"
              },
              "note": "Open the \"billing\" settings section."
            }
          ],
          "description": "Activate the tile with the given id (navigates or fires its select handler).",
          "descriptionKey": "ui.agent.navGrid.actions.openItem"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "nav-grid",
          "description": "Marks the NavGrid nav landmark."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop. Required to address a specific grid from the agent."
        },
        "item": {
          "attr": "data-nav-item-id",
          "sourceProp": "item id",
          "description": "Stable opaque id of a tile, sourced from each item.id. open_item targets this attribute."
        }
      }
    },
    {
      "kind": "component",
      "id": "navigation-menu",
      "capabilities": [
        "select_single",
        "navigate",
        "open",
        "close"
      ],
      "state": [
        {
          "name": "activeItem",
          "type": "string | null",
          "description": "Id of the currently-active top-level navigation item, or null when none is active.",
          "descriptionKey": "ui.agent.navigationMenu.state.activeItem"
        },
        {
          "name": "isOpen",
          "type": "boolean",
          "description": "Whether a dropdown / mega-menu panel is currently open.",
          "descriptionKey": "ui.agent.navigationMenu.state.isOpen"
        }
      ],
      "actions": [
        {
          "name": "select_item",
          "safety": "read",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "Stable opaque top-level item id (emitted as data-nav-id)."
              }
            },
            "required": [
              "id"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "id": "products"
              },
              "note": "Open the \"products\" menu."
            }
          ],
          "description": "Activate (open) the top-level item with the given id.",
          "descriptionKey": "ui.agent.navigationMenu.actions.selectItem"
        },
        {
          "name": "open",
          "safety": "read",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "Stable opaque top-level item id whose panel to open (data-nav-id)."
              }
            },
            "required": [
              "id"
            ]
          },
          "idempotent": true,
          "description": "Open the dropdown / mega-menu panel for the given top-level item id.",
          "descriptionKey": "ui.agent.navigationMenu.actions.open"
        },
        {
          "name": "close",
          "safety": "read",
          "idempotent": true,
          "description": "Close any open dropdown / mega-menu panel.",
          "descriptionKey": "ui.agent.navigationMenu.actions.close"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "navigation-menu",
          "description": "Marks the NavigationMenu root."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop. Required to address a specific menu from the agent."
        },
        "item": {
          "attr": "data-nav-id",
          "description": "Stable opaque id of a top-level navigation item. Selection / open targets this attribute."
        }
      }
    },
    {
      "kind": "component",
      "id": "note-timeline",
      "capabilities": [],
      "state": [
        {
          "name": "notes",
          "type": "Array<{ id?: string; pinned: boolean; flagged: boolean; clinical: boolean }>",
          "description": "Structural snapshot of the rendered rows: ids and flags only, never note content or author.",
          "descriptionKey": "ui.agent.noteTimeline.state.notes"
        },
        {
          "name": "visibleCount",
          "type": "number",
          "description": "How many notes are rendered, after the maxItems cap is applied.",
          "descriptionKey": "ui.agent.noteTimeline.state.visibleCount"
        }
      ],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "note-timeline",
          "description": "Marks the NoteTimeline root. Emits data-empty when there is nothing to show."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop — addresses a specific timeline."
        }
      }
    },
    {
      "kind": "component",
      "id": "notes-panel",
      "capabilities": [
        "submit"
      ],
      "state": [
        {
          "name": "notes",
          "type": "Array<{ id?: string; pinned: boolean; flagged: boolean; clinical: boolean; deleted: boolean }>",
          "description": "Timeline note ids + pinned / flagged / clinical / deleted flags. Never the note body or author (both PHI). A note whose delete is in flight is left out; a pin or flag in flight is reported with its new value. A deleted note takes no pin or flag.",
          "descriptionKey": "ui.agent.notesPanel.state.notes"
        },
        {
          "name": "canAddClinical",
          "type": "boolean",
          "description": "Whether the current user may write clinical notes (the practice_add_clinical_note permission gate).",
          "descriptionKey": "ui.agent.notesPanel.state.canAddClinical"
        },
        {
          "name": "currentNoteId",
          "type": "string | null",
          "description": "Id of the note the host has addressed — the one marked, scrolled to and focused. Null when none is. An id only, never note content.",
          "descriptionKey": "ui.agent.notesPanel.state.currentNoteId"
        }
      ],
      "actions": [
        {
          "name": "add_note",
          "safety": "phi",
          "argsType": "{ content: string; clinical: boolean }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "content": {
                "type": "string",
                "description": "Note body. Rich HTML for the rich composer, else plain text."
              },
              "clinical": {
                "type": "boolean",
                "description": "Whether the note is clinical. Requires the clinical-note permission; the submission is dropped when the gate is closed."
              }
            },
            "required": [
              "content",
              "clinical"
            ]
          },
          "openWorld": true,
          "examples": [
            {
              "args": {
                "content": "Patient reported improvement.",
                "clinical": true
              },
              "note": "Add a clinical note."
            }
          ],
          "description": "Compose and commit a new note. A clinical note requires the clinical-note permission (read canAddClinical first).",
          "descriptionKey": "ui.agent.notesPanel.actions.addNote"
        },
        {
          "name": "toggle_pin",
          "safety": "write",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              }
            },
            "required": [
              "id"
            ]
          },
          "idempotent": false,
          "openWorld": true,
          "errors": [
            "The panel offers no pin here: no onTogglePin, no note with this id, a deleted note, or actions.pin is false.",
            "A pin or delete for this note is still pending. Read notes again once it has settled.",
            "The host refused the change. The pin is restored and the panel shows the host's message."
          ],
          "description": "Toggle the pinned state of the note with the given id. Returns the host's promise; a refusal restores the pin and the panel shows the host's message. Rejects without reaching the host when the panel refuses: a deleted note, actions.pin false, or a write for the note still pending.",
          "descriptionKey": "ui.agent.notesPanel.actions.togglePin"
        },
        {
          "name": "toggle_flag",
          "safety": "write",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              }
            },
            "required": [
              "id"
            ]
          },
          "idempotent": false,
          "openWorld": true,
          "errors": [
            "The panel offers no flag here: no onToggleFlag, no note with this id, or a deleted note.",
            "A flag or delete for this note is still pending. Read notes again once it has settled.",
            "The host refused the change. The flag is restored and the panel shows the host's message."
          ],
          "description": "Toggle the flagged state of the note with the given id. Returns the host's promise; a refusal restores the flag and the panel shows the host's message. Rejects without reaching the host when the panel refuses: a deleted note, or a write for the note still pending.",
          "descriptionKey": "ui.agent.notesPanel.actions.toggleFlag"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "notes-panel",
          "description": "Marks the NotesPanel region."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop. Required to address a specific notes panel from the agent."
        },
        "item": {
          "attr": "data-note-id",
          "description": "Stable note id on each rendered note row. Row controls carry data-note-action: edit, delete, pin or flag."
        }
      }
    },
    {
      "kind": "component",
      "id": "notice-group",
      "capabilities": [
        "expand"
      ],
      "state": [
        {
          "name": "noteCount",
          "type": "number",
          "description": "How many folding notes (not errors or progress notices) are still shown, dismissed ones excluded.",
          "descriptionKey": "ui.agent.noticeGroup.state.noteCount"
        },
        {
          "name": "grouped",
          "type": "boolean",
          "description": "True while the notes sit behind one summary row (two or more notes).",
          "descriptionKey": "ui.agent.noticeGroup.state.grouped"
        },
        {
          "name": "open",
          "type": "boolean",
          "description": "Whether the summary row is open (expanded), so every note is visible.",
          "descriptionKey": "ui.agent.noticeGroup.state.open"
        }
      ],
      "actions": [
        {
          "name": "set_open",
          "safety": "read",
          "argsType": "open",
          "argsSchema": {
            "type": "object",
            "properties": {
              "open": {
                "type": "boolean",
                "description": "True to show every note, false to fold them."
              }
            },
            "required": [
              "open"
            ]
          },
          "returns": "boolean (applied)",
          "returnsSchema": {
            "type": "boolean",
            "description": "True when applied (with a controlled open, when asked of the host); false when there is no summary row (fewer than two notes)."
          },
          "idempotent": true,
          "errors": [
            "Fewer than two notes (grouped is false): returns false."
          ],
          "description": "Open (expand) or fold the notes behind the summary row. With a controlled open the host decides.",
          "descriptionKey": "ui.agent.noticeGroup.actions.setOpen"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "notice-group",
          "description": "Marks the NoticeGroup. Carries data-grouped=\"true\" while the notes fold behind the summary row, whose Alert carries data-notice-group-summary."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "notification-card",
      "capabilities": [
        "dismiss"
      ],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "notification-card",
          "description": "Marks the element as a kit NotificationCard. The card root also emits data-component-id sourced from item.id and data-read with the current read flag."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "item.id",
          "description": "Sourced from item.id — the stable notification identifier."
        }
      }
    },
    {
      "kind": "component",
      "id": "notification-tray",
      "capabilities": [
        "open",
        "close",
        "select_single",
        "dismiss",
        "navigate"
      ],
      "state": [
        {
          "name": "items",
          "type": "Array<{ id: string; read: boolean }>",
          "description": "Currently-displayed notifications. Ids + read flag only — no PHI.",
          "descriptionKey": "ui.agent.notificationTray.state.items"
        },
        {
          "name": "unreadCount",
          "type": "number",
          "description": "Badge unread count surfaced by the host.",
          "descriptionKey": "ui.agent.notificationTray.state.unreadCount"
        },
        {
          "name": "isOpen",
          "type": "boolean",
          "description": "Whether the dropdown panel is currently open.",
          "descriptionKey": "ui.agent.notificationTray.state.isOpen"
        }
      ],
      "actions": [
        {
          "name": "open",
          "safety": "read",
          "idempotent": true,
          "description": "Open the notification panel.",
          "descriptionKey": "ui.agent.notificationTray.actions.open"
        },
        {
          "name": "close",
          "safety": "read",
          "idempotent": true,
          "description": "Close the notification panel.",
          "descriptionKey": "ui.agent.notificationTray.actions.close"
        },
        {
          "name": "select_item",
          "safety": "read",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              }
            },
            "required": [
              "id"
            ]
          },
          "idempotent": true,
          "errors": [
            "No notification matches the given id."
          ],
          "examples": [
            {
              "args": {
                "id": "notif-1"
              }
            }
          ],
          "description": "Activate the notification with the given id.",
          "descriptionKey": "ui.agent.notificationTray.actions.selectItem"
        },
        {
          "name": "mark_read",
          "safety": "write",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              }
            },
            "required": [
              "id"
            ]
          },
          "idempotent": true,
          "errors": [
            "No notification matches the given id."
          ],
          "examples": [
            {
              "args": {
                "id": "notif-1"
              }
            }
          ],
          "description": "Request the host to mark a notification as read.",
          "descriptionKey": "ui.agent.notificationTray.actions.markRead"
        },
        {
          "name": "dismiss",
          "safety": "destructive",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              }
            },
            "required": [
              "id"
            ]
          },
          "idempotent": true,
          "errors": [
            "No notification matches the given id."
          ],
          "examples": [
            {
              "args": {
                "id": "notif-1"
              }
            }
          ],
          "description": "Request the host to dismiss the notification with the given id.",
          "descriptionKey": "ui.agent.notificationTray.actions.dismiss"
        },
        {
          "name": "mark_all_read",
          "safety": "write",
          "idempotent": true,
          "description": "Request the host to mark every notification as read.",
          "descriptionKey": "ui.agent.notificationTray.actions.markAllRead"
        },
        {
          "name": "view_all",
          "safety": "read",
          "idempotent": true,
          "description": "Navigate to the full notification list.",
          "descriptionKey": "ui.agent.notificationTray.actions.viewAll"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "notification-tray",
          "description": "Marks the NotificationTray wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop. Required to address a specific tray from the agent."
        },
        "item": {
          "attr": "data-notification-id",
          "description": "Stable notification id emitted on each rendered NotificationCard inside the tray."
        }
      }
    },
    {
      "kind": "component",
      "id": "number-input",
      "capabilities": [
        "set_value"
      ],
      "state": [
        {
          "name": "value",
          "type": "number | null",
          "description": "Current numeric value, or null when empty.",
          "descriptionKey": "ui.agent.numberInput.state.value"
        },
        {
          "name": "isEmpty",
          "type": "boolean",
          "description": "Whether the input has no value.",
          "descriptionKey": "ui.agent.numberInput.state.isEmpty"
        }
      ],
      "actions": [
        {
          "name": "set_value",
          "safety": "write",
          "argsType": "{ value: number | null }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "value": {
                "type": [
                  "number",
                  "null"
                ]
              }
            },
            "required": [
              "value"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "value": 42
              }
            },
            {
              "args": {
                "value": null
              }
            }
          ],
          "description": "Replace the numeric value, or pass null to clear.",
          "descriptionKey": "ui.agent.numberInput.actions.setValue"
        },
        {
          "name": "clear",
          "safety": "destructive",
          "idempotent": true,
          "description": "Empty the input. Loses any typed value.",
          "descriptionKey": "ui.agent.numberInput.actions.clear"
        },
        {
          "name": "focus",
          "safety": "read",
          "idempotent": true,
          "description": "Move keyboard focus to the input.",
          "descriptionKey": "ui.agent.numberInput.actions.focus"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "number-input",
          "description": "Marks the NumberInput wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "operator-hero",
      "capabilities": [],
      "state": [
        {
          "name": "name",
          "type": "string",
          "description": "Operator display name currently rendered.",
          "descriptionKey": "ui.agent.operatorHero.state.name"
        },
        {
          "name": "hasColor",
          "type": "boolean",
          "description": "Whether a calendar-colour identity dot is rendered. Structural flag only — never the colour id or any PHI.",
          "descriptionKey": "ui.agent.operatorHero.state.hasColor"
        }
      ],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "operator-hero",
          "description": "Marks the OperatorHero root region."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "optical-prescription",
      "capabilities": [
        "pick",
        "edit_inline",
        "set_value"
      ],
      "state": [
        {
          "name": "prescription",
          "type": "object",
          "description": "Current prescription — refraction rows per band/eye plus PD, lens type and axis system. The free-text note is PHI and omitted; read it via get_notes.",
          "descriptionKey": "ui.agent.opticalPrescription.state.prescription"
        },
        {
          "name": "bands",
          "type": "string[]",
          "description": "Distance bands carrying at least one refraction value (far / intermediate / near).",
          "descriptionKey": "ui.agent.opticalPrescription.state.bands"
        }
      ],
      "actions": [
        {
          "name": "focus_eye",
          "safety": "read",
          "argsType": "{ eye: Eye; band?: DistanceBand }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "eye": {
                "enum": [
                  "od",
                  "os"
                ],
                "description": "Eye — `od` (right eye) or `os` (left eye)."
              },
              "band": {
                "enum": [
                  "far",
                  "intermediate",
                  "near"
                ],
                "description": "Distance band — `far` (per lontano), `intermediate`, `near` (per vicino)."
              }
            },
            "required": [
              "eye"
            ]
          },
          "idempotent": true,
          "description": "Move focus to an eye's row (first editable cell in interactive mode), optionally within a specific band.",
          "descriptionKey": "ui.agent.opticalPrescription.actions.focusEye"
        },
        {
          "name": "get_row",
          "safety": "read",
          "argsType": "{ band: DistanceBand; eye: Eye }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "band": {
                "enum": [
                  "far",
                  "intermediate",
                  "near"
                ],
                "description": "Distance band — `far` (per lontano), `intermediate`, `near` (per vicino)."
              },
              "eye": {
                "enum": [
                  "od",
                  "os"
                ],
                "description": "Eye — `od` (right eye) or `os` (left eye)."
              }
            },
            "required": [
              "band",
              "eye"
            ]
          },
          "returns": "RefractionRow | undefined",
          "returnsSchema": {
            "type": "object",
            "properties": {
              "sphere": {
                "type": "number"
              },
              "cylinder": {
                "type": "number"
              },
              "axis": {
                "type": "number",
                "minimum": 0,
                "maximum": 180
              },
              "add": {
                "type": "number"
              },
              "prism": {
                "type": "number"
              },
              "base": {
                "enum": [
                  "up",
                  "down",
                  "in",
                  "out"
                ]
              }
            }
          },
          "idempotent": true,
          "description": "Read one eye's refraction row at a distance band.",
          "descriptionKey": "ui.agent.opticalPrescription.actions.getRow"
        },
        {
          "name": "get_notes",
          "safety": "phi",
          "returns": "string",
          "returnsSchema": {
            "type": "string"
          },
          "idempotent": true,
          "description": "Read the free-text clinical note on the prescription.",
          "descriptionKey": "ui.agent.opticalPrescription.actions.getNotes"
        },
        {
          "name": "set_cell",
          "safety": "write",
          "argsType": "{ band: DistanceBand; eye: Eye; field: keyof RefractionRow; value: number | PrismBase | null }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "band": {
                "enum": [
                  "far",
                  "intermediate",
                  "near"
                ],
                "description": "Distance band — `far` (per lontano), `intermediate`, `near` (per vicino)."
              },
              "eye": {
                "enum": [
                  "od",
                  "os"
                ],
                "description": "Eye — `od` (right eye) or `os` (left eye)."
              },
              "field": {
                "enum": [
                  "sphere",
                  "cylinder",
                  "axis",
                  "add",
                  "prism",
                  "base"
                ],
                "description": "Refraction column — dioptric `sphere` / `cylinder` / `add` (0.25 steps), `axis` (0–180°), `prism`, or `base` (a direction enum)."
              },
              "value": {
                "description": "New cell value — a number for the dioptric/axis/prism columns, a base-direction string for `base`, or null to clear."
              }
            },
            "required": [
              "band",
              "eye",
              "field",
              "value"
            ]
          },
          "idempotent": true,
          "description": "Set (or clear, with null) a single refraction cell — sphere / cylinder / axis / add / prism / base.",
          "descriptionKey": "ui.agent.opticalPrescription.actions.setCell"
        },
        {
          "name": "set_value",
          "safety": "write",
          "argsType": "{ value: OpticalPrescriptionValue }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "value": {
                "type": "object",
                "properties": {
                  "bands": {
                    "type": "object",
                    "description": "Refraction rows keyed by band (`far` / `intermediate` / `near`) then eye (`od` / `os`)."
                  },
                  "pd": {
                    "type": "number",
                    "description": "Interpupillary distance, mm."
                  },
                  "pdRight": {
                    "type": "number",
                    "description": "Monocular PD, nose centre → OD pupil, mm."
                  },
                  "pdLeft": {
                    "type": "number",
                    "description": "Monocular PD, nose centre → OS pupil, mm."
                  },
                  "lensType": {
                    "enum": [
                      "single-vision",
                      "bifocal",
                      "progressive"
                    ]
                  },
                  "axisSystem": {
                    "enum": [
                      "tabo",
                      "int"
                    ]
                  },
                  "notes": {
                    "type": "string",
                    "description": "Free-text note — PHI."
                  }
                },
                "required": [
                  "bands"
                ]
              }
            },
            "required": [
              "value"
            ]
          },
          "idempotent": true,
          "description": "Replace the entire prescription value.",
          "descriptionKey": "ui.agent.opticalPrescription.actions.setValue"
        },
        {
          "name": "clear_band",
          "safety": "destructive",
          "argsType": "{ band: DistanceBand }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "band": {
                "enum": [
                  "far",
                  "intermediate",
                  "near"
                ],
                "description": "Distance band — `far` (per lontano), `intermediate`, `near` (per vicino)."
              }
            },
            "required": [
              "band"
            ]
          },
          "idempotent": true,
          "description": "Clear every refraction row in a distance band.",
          "descriptionKey": "ui.agent.opticalPrescription.actions.clearBand"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "optical-prescription"
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        },
        "item": {
          "attr": "data-eye",
          "description": "Each refraction row carries its eye (`od` / `os`) as `data-eye` and its distance band as `data-band`; each editable cell carries the column key as `data-field`. The root `data-mode` attribute exposes interactive vs display. Standard chart figures carry `data-chart` (`tabo` / `powerCross` / `pd` / `prismBase`) plus `data-eye` on the per-eye ones."
        }
      }
    },
    {
      "kind": "component",
      "id": "otp-input",
      "capabilities": [
        "set_value"
      ],
      "state": [
        {
          "name": "value",
          "type": "string",
          "description": "Current digits entered, packed into a single string.",
          "descriptionKey": "ui.agent.otpInput.state.value"
        },
        {
          "name": "isComplete",
          "type": "boolean",
          "description": "Whether all required digits have been entered.",
          "descriptionKey": "ui.agent.otpInput.state.isComplete"
        }
      ],
      "actions": [
        {
          "name": "set_value",
          "safety": "write",
          "argsType": "{ value: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "value": {
                "type": "string",
                "description": "The digits to fill, packed into a single string (one char per cell)."
              }
            },
            "required": [
              "value"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "value": "123456"
              }
            }
          ],
          "description": "Replace the entered digits.",
          "descriptionKey": "ui.agent.otpInput.actions.setValue"
        },
        {
          "name": "clear",
          "safety": "destructive",
          "idempotent": true,
          "description": "Empty all digit cells. Loses any typed value.",
          "descriptionKey": "ui.agent.otpInput.actions.clear"
        },
        {
          "name": "focus",
          "safety": "read",
          "idempotent": true,
          "description": "Move keyboard focus to the active digit cell.",
          "descriptionKey": "ui.agent.otpInput.actions.focus"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "otp-input",
          "description": "Marks the OTPInput wrapper. Completion is observable via state.isComplete; the host onComplete callback fires once when all digits are filled."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "pagination",
      "capabilities": [
        "paginate",
        "range_navigate"
      ],
      "state": [
        {
          "name": "currentPage",
          "type": "number",
          "description": "Current page index (1-based).",
          "descriptionKey": "ui.agent.pagination.state.currentPage"
        },
        {
          "name": "totalPages",
          "type": "number",
          "description": "Total number of pages.",
          "descriptionKey": "ui.agent.pagination.state.totalPages"
        }
      ],
      "actions": [
        {
          "name": "go_to_page",
          "safety": "read",
          "argsType": "{ page: number }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "page": {
                "type": "integer",
                "minimum": 1,
                "description": "1-indexed target page."
              }
            },
            "required": [
              "page"
            ]
          },
          "idempotent": true,
          "errors": [
            "Page is out of range (clamped to [1, totalPages])."
          ],
          "examples": [
            {
              "args": {
                "page": 3
              }
            }
          ],
          "description": "Navigate to a specific 1-indexed page.",
          "descriptionKey": "ui.agent.pagination.actions.goToPage"
        },
        {
          "name": "next",
          "safety": "read",
          "description": "Advance to the next page.",
          "descriptionKey": "ui.agent.pagination.actions.next"
        },
        {
          "name": "previous",
          "safety": "read",
          "description": "Step back to the previous page.",
          "descriptionKey": "ui.agent.pagination.actions.previous"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "pagination"
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "panel-header",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "panel-header",
          "description": "Marks the element as a kit PanelHeader."
        }
      }
    },
    {
      "kind": "component",
      "id": "panel-subview",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "panel-subview",
          "description": "Marks the element as a kit PanelSubview."
        }
      }
    },
    {
      "kind": "component",
      "id": "password-input",
      "capabilities": [
        "set_value"
      ],
      "state": [
        {
          "name": "value",
          "type": "string",
          "description": "Current password value. Never log or persist this off-device.",
          "descriptionKey": "ui.agent.passwordInput.state.value"
        },
        {
          "name": "isEmpty",
          "type": "boolean",
          "description": "Whether the input has no value.",
          "descriptionKey": "ui.agent.passwordInput.state.isEmpty"
        },
        {
          "name": "isRevealed",
          "type": "boolean",
          "description": "Whether the password is currently shown in plain text.",
          "descriptionKey": "ui.agent.passwordInput.state.isRevealed"
        }
      ],
      "actions": [
        {
          "name": "set_value",
          "safety": "write",
          "argsType": "{ value: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "value": {
                "type": "string",
                "description": "New password. Sensitive — never log or persist off-device."
              }
            },
            "required": [
              "value"
            ]
          },
          "idempotent": true,
          "description": "Replace the password value.",
          "descriptionKey": "ui.agent.passwordInput.actions.setValue"
        },
        {
          "name": "clear",
          "safety": "destructive",
          "idempotent": true,
          "description": "Empty the input. Loses any typed value.",
          "descriptionKey": "ui.agent.passwordInput.actions.clear"
        },
        {
          "name": "focus",
          "safety": "read",
          "idempotent": true,
          "description": "Move keyboard focus to the input.",
          "descriptionKey": "ui.agent.passwordInput.actions.focus"
        },
        {
          "name": "toggle_visibility",
          "safety": "read",
          "description": "Toggle between masked and plain-text display.",
          "descriptionKey": "ui.agent.passwordInput.actions.toggleVisibility"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "password-input",
          "description": "Marks the PasswordInput wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "patient-details",
      "capabilities": [
        "view_change",
        "set_value"
      ],
      "state": [
        {
          "name": "visibleFieldOrder",
          "type": "string[]",
          "description": "Ordered list of visible field KEYS (e.g. \"fiscalCode\"). Never a field value.",
          "descriptionKey": "ui.agent.patientDetails.state.visibleFieldOrder"
        },
        {
          "name": "patientId",
          "type": "string | undefined",
          "description": "Opaque patient id the panel is bound to. No patient-identifiable data.",
          "descriptionKey": "ui.agent.patientDetails.state.patientId"
        }
      ],
      "actions": [
        {
          "name": "set_visible_fields",
          "safety": "write",
          "argsType": "{ fieldIds: string[] }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "fieldIds": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            },
            "required": [
              "fieldIds"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "fieldIds": [
                  "lastName",
                  "firstName",
                  "phone",
                  "email"
                ]
              },
              "note": "Show only name + contact fields."
            }
          ],
          "description": "Set which fields are visible (and their order). Unknown ids are ignored.",
          "descriptionKey": "ui.agent.patientDetails.actions.setVisibleFields"
        },
        {
          "name": "set_field_order",
          "safety": "write",
          "argsType": "{ orderedIds: string[] }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "orderedIds": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            },
            "required": [
              "orderedIds"
            ]
          },
          "idempotent": true,
          "description": "Reorder the visible fields. Order within a section is honoured; sections stay fixed.",
          "descriptionKey": "ui.agent.patientDetails.actions.setFieldOrder"
        },
        {
          "name": "update_field",
          "safety": "phi",
          "argsType": "{ fieldId: string; value: unknown }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "fieldId": {
                "type": "string"
              },
              "value": {}
            },
            "required": [
              "fieldId",
              "value"
            ]
          },
          "idempotent": true,
          "openWorld": true,
          "errors": [
            "no-save-handler",
            "validation-failed",
            "permission-denied"
          ],
          "examples": [
            {
              "args": {
                "fieldId": "job",
                "value": "Architect"
              },
              "note": "Update the patient’s occupation."
            }
          ],
          "description": "Write a patient field value via the consumer's audited save path. Subject to the same permissions and validation as a human edit.",
          "descriptionKey": "ui.agent.patientDetails.actions.updateField"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "patient-details",
          "description": "Marks the PatientDetails root region."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop. Addresses a specific panel."
        },
        "item": {
          "attr": "data-field-id",
          "description": "Stable field KEY on each row. Never the field value (no PHI in the DOM hook)."
        }
      }
    },
    {
      "kind": "component",
      "id": "patient-search",
      "capabilities": [
        "filter"
      ],
      "state": [
        {
          "name": "variant",
          "type": "string",
          "description": "Active variant — one of `who-where`, `who-where-when`, `faceted`, `discovery`.",
          "descriptionKey": "ui.agent.patientSearch.state.variant"
        }
      ],
      "actions": [
        {
          "name": "reset",
          "safety": "write",
          "idempotent": true,
          "description": "Clear the current search query (WHO, WHERE, WHEN, facets, geo) via the consumer-owned onChange.",
          "descriptionKey": "ui.agent.patientSearch.actions.reset"
        },
        {
          "name": "focus_primary",
          "safety": "read",
          "idempotent": true,
          "description": "Move keyboard focus to the most-relevant search field for the current variant.",
          "descriptionKey": "ui.agent.patientSearch.actions.focusPrimary"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "patient-search",
          "description": "Marks the PatientSearch root region."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "patient-summary-card",
      "capabilities": [],
      "state": [
        {
          "name": "summary",
          "type": "{ id?: string; hasUnpaid: boolean; unsignedDocumentsCount: number; highlightedAnamnesisCount: number; aiConsentGranted: boolean }",
          "description": "Structural summary of the patient card — identifiers, counts, and consent flags only. Never patient identity or clinical content.",
          "descriptionKey": "ui.agent.patientSummaryCard.state.summary"
        }
      ],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "patient-summary-card",
          "description": "Marks the PatientSummaryCard root region."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "payment-card",
      "capabilities": [],
      "state": [
        {
          "name": "number",
          "type": "string",
          "description": "Payment number / reference currently rendered.",
          "descriptionKey": "ui.agent.paymentCard.state.number"
        },
        {
          "name": "state",
          "type": "'debt' | 'to-invoice' | 'settled'",
          "description": "Resolved headline financial state. Structural state only — never patient identity.",
          "descriptionKey": "ui.agent.paymentCard.state.state"
        }
      ],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "payment-card",
          "description": "Marks the PaymentCard root region."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop. Addresses a specific card."
        }
      }
    },
    {
      "kind": "component",
      "id": "payment-form",
      "capabilities": [
        "submit"
      ],
      "state": [
        {
          "name": "status",
          "type": "'idle' | 'processing' | 'succeeded' | 'failed'",
          "description": "Lifecycle of the current payment attempt. `succeeded` is only reached once Stripe confirmed the PaymentIntent; `failed` covers validation, decline and processor errors alike. Still `idle` after `submit` means the attempt never fired — Stripe had not mounted.",
          "descriptionKey": "ui.agent.paymentForm.state.status"
        },
        {
          "name": "complete",
          "type": "boolean",
          "description": "True when Stripe reports the payment fields, and any required billing address, as complete. Read this before `submit` — outside preview mode the submit control is disabled while it is false, so the call will not be accepted.",
          "descriptionKey": "ui.agent.paymentForm.state.complete"
        },
        {
          "name": "errorKey",
          "type": "string | null",
          "description": "i18n key of the current error (e.g. `payment.error.cardDeclined`), or null. The key is the structural datum — the translated message is free text and is never exposed.",
          "descriptionKey": "ui.agent.paymentForm.state.errorKey"
        },
        {
          "name": "paymentIntentId",
          "type": "string | null",
          "description": "Opaque Stripe PaymentIntent id once a charge succeeded, else null. The receipt — the attribution handle for the money that moved. Never the client secret.",
          "descriptionKey": "ui.agent.paymentForm.state.paymentIntentId"
        }
      ],
      "actions": [
        {
          "name": "submit",
          "safety": "destructive",
          "returns": "Promise<void>",
          "openWorld": true,
          "errors": [
            "Validation failed (incomplete or invalid card details) — `status` is \"failed\", `errorKey` names which.",
            "Payment was declined by the processor — `status` is \"failed\", `errorKey` is `payment.error.cardDeclined`.",
            "Network or processor error during the charge — `status` is \"failed\".",
            "Stripe had not mounted, so nothing was attempted — `status` is still \"idle\"."
          ],
          "description": "Submit the payment. Charges the configured payment method — irreversible. Resolves once the attempt has settled; the outcome is never in the resolved value, so read `status`, then `errorKey` on failure or `paymentIntentId` on success.",
          "descriptionKey": "ui.agent.paymentForm.actions.submit"
        },
        {
          "name": "reset",
          "safety": "destructive",
          "idempotent": true,
          "description": "Clear recoverable errors and return their status to \"idle\". Stripe fields remain unchanged. Pending or paid attempts cannot be reset and require a new session.",
          "descriptionKey": "ui.agent.paymentForm.actions.reset"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "payment-form"
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "payment-request-card",
      "capabilities": [],
      "state": [
        {
          "name": "status",
          "type": "'new' | 'authorization_requested' | 'authorized' | 'paid' | 'failed' | 'cancelled'",
          "description": "Current lifecycle status of the payment request. Structural state only.",
          "descriptionKey": "ui.agent.paymentRequestCard.state.status"
        }
      ],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "payment-request-card",
          "description": "Marks the PaymentRequestCard root region."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop. Addresses a specific request card."
        }
      }
    },
    {
      "kind": "component",
      "id": "pdf-viewer",
      "capabilities": [
        "paginate",
        "set_value",
        "filter"
      ],
      "state": [
        {
          "name": "status",
          "type": "'loading' | 'ready' | 'error'",
          "description": "Whether the document has loaded. Read this first — every action is a silent no-op while the viewer is loading or has failed.",
          "descriptionKey": "ui.agent.pdfViewer.state.status"
        },
        {
          "name": "currentPage",
          "type": "number",
          "description": "1-indexed page currently in view. The read-back for `go_to_page`, which clamps out-of-range requests silently.",
          "descriptionKey": "ui.agent.pdfViewer.state.currentPage"
        },
        {
          "name": "pageCount",
          "type": "number",
          "description": "Number of pages in the loaded document, or 0 before it loads. Range-check against this before calling `go_to_page` rather than discovering the clamp after the fact.",
          "descriptionKey": "ui.agent.pdfViewer.state.pageCount"
        },
        {
          "name": "zoom",
          "type": "'fit-width' | 'fit-page' | 'actual-size' | number",
          "description": "Zoom preset or numeric scale factor currently applied. The read-back for `set_zoom`.",
          "descriptionKey": "ui.agent.pdfViewer.state.zoom"
        },
        {
          "name": "searchMatchCount",
          "type": "number",
          "description": "Number of matches for the active search query — 0 when nothing matched or no search is running. A count only; the matched text is never exposed.",
          "descriptionKey": "ui.agent.pdfViewer.state.searchMatchCount"
        }
      ],
      "actions": [
        {
          "name": "go_to_page",
          "safety": "read",
          "argsType": "{ page: number }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "page": {
                "type": "integer",
                "minimum": 1,
                "description": "1-indexed target page."
              }
            },
            "required": [
              "page"
            ]
          },
          "idempotent": true,
          "errors": [
            "No-op while `status` is not \"ready\" — the document has not loaded.",
            "A page outside 1..`pageCount` is silently clamped into range; read `currentPage` back to see where it landed."
          ],
          "examples": [
            {
              "args": {
                "page": 2
              }
            }
          ],
          "description": "Navigate to a specific 1-indexed page. Check `pageCount` first — an out-of-range page is clamped silently, and the call is a no-op until `status` is \"ready\".",
          "descriptionKey": "ui.agent.pdfViewer.actions.goToPage"
        },
        {
          "name": "set_zoom",
          "safety": "read",
          "argsType": "{ zoom: PDFZoomPreset }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "zoom": {
                "description": "Either a named preset ('fit-width' | 'fit-page' | 'actual-size') or a numeric scale factor (e.g. 1.5).",
                "oneOf": [
                  {
                    "enum": [
                      "fit-width",
                      "fit-page",
                      "actual-size"
                    ]
                  },
                  {
                    "type": "number",
                    "exclusiveMinimum": 0
                  }
                ]
              }
            },
            "required": [
              "zoom"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "zoom": "fit-width"
              }
            },
            {
              "args": {
                "zoom": 1.5
              }
            }
          ],
          "description": "Apply a zoom preset or numeric scale factor.",
          "descriptionKey": "ui.agent.pdfViewer.actions.setZoom"
        },
        {
          "name": "search",
          "safety": "read",
          "argsType": "{ query: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "query": {
                "type": "string",
                "description": "Text to find and highlight in the loaded document."
              }
            },
            "required": [
              "query"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "query": "consent"
              }
            }
          ],
          "description": "Search the document for the given query and highlight matches. Read the `searchMatchCount` slot afterwards — the action itself returns nothing.",
          "descriptionKey": "ui.agent.pdfViewer.actions.search"
        },
        {
          "name": "print",
          "safety": "read",
          "description": "Open the browser print dialog for the document.",
          "descriptionKey": "ui.agent.pdfViewer.actions.print"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "pdf-viewer"
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "periodontal-chart",
      "capabilities": [
        "pick",
        "set_value",
        "edit_inline"
      ],
      "state": [
        {
          "name": "indices",
          "type": "object",
          "description": "Derived whole-mouth indices: mean probing depth, mean attachment level, plaque %, bleeding %, scored-site and deep-pocket counts. Aggregates only — no per-site or patient data.",
          "descriptionKey": "ui.agent.periodontalChart.state.indices"
        },
        {
          "name": "findings",
          "type": "object[]",
          "description": "Narratable per-tooth problem list — one entry per flagged tooth (missing, implant, a pocket at/above the moderate threshold, bleeding, suppuration, mobility ≥ 1, or furcation), in clinical order with each tooth’s pockets deepest-first. Each entry carries fdi, status, severity, maxPocketDepthMm, pockets, bleeding/plaque/suppuration sites, maxRecessionMm, mobility and furcation. Read this to summarise the chart aloud. Structural readings + FDI ids only — never the free-text note or patient identity.",
          "descriptionKey": "ui.agent.periodontalChart.state.findings"
        },
        {
          "name": "missingTeeth",
          "type": "string[]",
          "description": "FDI ids of every tooth flagged as missing.",
          "descriptionKey": "ui.agent.periodontalChart.state.missingTeeth"
        },
        {
          "name": "chartedTeeth",
          "type": "string[]",
          "description": "FDI ids of teeth carrying at least one probing reading or flag. Identifiers only — never patient identity or the free-text note.",
          "descriptionKey": "ui.agent.periodontalChart.state.chartedTeeth"
        }
      ],
      "actions": [
        {
          "name": "focus_site",
          "safety": "read",
          "argsType": "{ fdi: string; site: PeriodontalSiteId; field: \"pocketDepthMm\" | \"recessionMm\" | \"bleeding\" | \"plaque\" }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "fdi": {
                "type": "string",
                "description": "FDI tooth id ('11'–'48' permanent, '51'–'85' primary)."
              },
              "site": {
                "enum": [
                  "db",
                  "b",
                  "mb",
                  "dl",
                  "l",
                  "ml"
                ],
                "description": "Probing site: (m/d)b = mesio-/disto-/mid buccal, (m/d)l = mesio-/disto-/mid lingual."
              },
              "field": {
                "enum": [
                  "pocketDepthMm",
                  "recessionMm",
                  "bleeding",
                  "plaque"
                ]
              }
            },
            "required": [
              "fdi",
              "site",
              "field"
            ]
          },
          "idempotent": true,
          "description": "Move focus to one per-site input: a probing measurement (pocket depth, recession) or the bleeding or plaque checkbox.",
          "descriptionKey": "ui.agent.periodontalChart.actions.focusSite"
        },
        {
          "name": "get_tooth",
          "safety": "read",
          "argsType": "{ fdi: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "fdi": {
                "type": "string",
                "description": "FDI tooth id ('11'–'48' permanent, '51'–'85' primary)."
              }
            },
            "required": [
              "fdi"
            ]
          },
          "returns": "object | null",
          "returnsSchema": {
            "type": [
              "object",
              "null"
            ]
          },
          "idempotent": true,
          "description": "Read one tooth’s structural readings (sites, flags, mobility, furcation). The free-text note is never returned.",
          "descriptionKey": "ui.agent.periodontalChart.actions.getTooth"
        },
        {
          "name": "get_indices",
          "safety": "read",
          "argsType": "{}",
          "argsSchema": {
            "type": "object",
            "properties": {}
          },
          "returns": "PeriodontalIndices",
          "returnsSchema": {
            "type": "object",
            "properties": {
              "meanPocketDepthMm": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "meanAttachmentLevelMm": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "plaquePercent": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "bleedingPercent": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "scoredSiteCount": {
                "type": "number"
              },
              "deepPocketCount": {
                "type": "number"
              }
            }
          },
          "idempotent": true,
          "description": "Read the derived whole-mouth summary indices.",
          "descriptionKey": "ui.agent.periodontalChart.actions.getIndices"
        },
        {
          "name": "get_findings",
          "safety": "read",
          "argsType": "{}",
          "argsSchema": {
            "type": "object",
            "properties": {}
          },
          "returns": "PeriodontalToothFinding[]",
          "returnsSchema": {
            "type": "array",
            "description": "One entry per flagged tooth, in clinical order; each tooth’s pockets are deepest-first.",
            "items": {
              "type": "object",
              "properties": {
                "fdi": {
                  "type": "string",
                  "description": "FDI tooth id ('11'–'48' permanent, '51'–'85' primary)."
                },
                "status": {
                  "enum": [
                    "present",
                    "missing",
                    "implant"
                  ],
                  "description": "Structural status of the tooth."
                },
                "severity": {
                  "enum": [
                    "normal",
                    "moderate",
                    "severe"
                  ],
                  "description": "Worst pocket severity band across the tooth."
                },
                "maxPocketDepthMm": {
                  "type": [
                    "integer",
                    "null"
                  ]
                },
                "pockets": {
                  "type": "array",
                  "description": "Sites at/above the moderate threshold, deepest first.",
                  "items": {
                    "type": "object",
                    "properties": {
                      "site": {
                        "enum": [
                          "db",
                          "b",
                          "mb",
                          "dl",
                          "l",
                          "ml"
                        ],
                        "description": "Probing site: (m/d)b = mesio-/disto-/mid buccal, (m/d)l = mesio-/disto-/mid lingual."
                      },
                      "pocketDepthMm": {
                        "type": "integer",
                        "description": "Whole millimetres — perio probing is recorded in integer mm."
                      },
                      "severity": {
                        "enum": [
                          "moderate",
                          "severe"
                        ]
                      }
                    }
                  }
                },
                "bleedingSites": {
                  "type": "array",
                  "items": {
                    "enum": [
                      "db",
                      "b",
                      "mb",
                      "dl",
                      "l",
                      "ml"
                    ],
                    "description": "Probing site: (m/d)b = mesio-/disto-/mid buccal, (m/d)l = mesio-/disto-/mid lingual."
                  }
                },
                "plaqueSites": {
                  "type": "array",
                  "items": {
                    "enum": [
                      "db",
                      "b",
                      "mb",
                      "dl",
                      "l",
                      "ml"
                    ],
                    "description": "Probing site: (m/d)b = mesio-/disto-/mid buccal, (m/d)l = mesio-/disto-/mid lingual."
                  }
                },
                "suppurationSites": {
                  "type": "array",
                  "items": {
                    "enum": [
                      "db",
                      "b",
                      "mb",
                      "dl",
                      "l",
                      "ml"
                    ],
                    "description": "Probing site: (m/d)b = mesio-/disto-/mid buccal, (m/d)l = mesio-/disto-/mid lingual."
                  }
                },
                "maxRecessionMm": {
                  "type": [
                    "number",
                    "null"
                  ]
                },
                "mobility": {
                  "type": [
                    "integer",
                    "null"
                  ],
                  "description": "Miller mobility grade 1–3, or null when none."
                },
                "furcation": {
                  "type": "array",
                  "items": {
                    "enum": [
                      "buccal",
                      "lingual"
                    ]
                  }
                }
              }
            }
          },
          "idempotent": true,
          "description": "Read the narratable per-tooth problem list (flagged teeth only). Use it to summarise the chart aloud — e.g. “46: 8 mm disto-buccal pocket, bleeding, grade 2 mobility”. Structural readings and FDI ids only; the free-text note is never returned.",
          "descriptionKey": "ui.agent.periodontalChart.actions.getFindings"
        },
        {
          "name": "set_depth",
          "safety": "write",
          "argsType": "{ fdi: string; site: PeriodontalSiteId; mm: number }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "fdi": {
                "type": "string",
                "description": "FDI tooth id ('11'–'48' permanent, '51'–'85' primary)."
              },
              "site": {
                "enum": [
                  "db",
                  "b",
                  "mb",
                  "dl",
                  "l",
                  "ml"
                ],
                "description": "Probing site: (m/d)b = mesio-/disto-/mid buccal, (m/d)l = mesio-/disto-/mid lingual."
              },
              "mm": {
                "type": "integer",
                "description": "Whole millimetres — perio probing is recorded in integer mm."
              }
            },
            "required": [
              "fdi",
              "site",
              "mm"
            ]
          },
          "idempotent": true,
          "description": "Record the probing pocket depth (mm) at a site.",
          "descriptionKey": "ui.agent.periodontalChart.actions.setDepth"
        },
        {
          "name": "set_recession",
          "safety": "write",
          "argsType": "{ fdi: string; site: PeriodontalSiteId; mm: number }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "fdi": {
                "type": "string",
                "description": "FDI tooth id ('11'–'48' permanent, '51'–'85' primary)."
              },
              "site": {
                "enum": [
                  "db",
                  "b",
                  "mb",
                  "dl",
                  "l",
                  "ml"
                ],
                "description": "Probing site: (m/d)b = mesio-/disto-/mid buccal, (m/d)l = mesio-/disto-/mid lingual."
              },
              "mm": {
                "type": "integer",
                "description": "Whole millimetres — perio probing is recorded in integer mm."
              }
            },
            "required": [
              "fdi",
              "site",
              "mm"
            ]
          },
          "idempotent": true,
          "description": "Record the gingival recession (mm) at a site.",
          "descriptionKey": "ui.agent.periodontalChart.actions.setRecession"
        },
        {
          "name": "toggle_bleeding",
          "safety": "write",
          "argsType": "{ fdi: string; site: PeriodontalSiteId; value: boolean }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "fdi": {
                "type": "string",
                "description": "FDI tooth id ('11'–'48' permanent, '51'–'85' primary)."
              },
              "site": {
                "enum": [
                  "db",
                  "b",
                  "mb",
                  "dl",
                  "l",
                  "ml"
                ],
                "description": "Probing site: (m/d)b = mesio-/disto-/mid buccal, (m/d)l = mesio-/disto-/mid lingual."
              },
              "value": {
                "type": "boolean"
              }
            },
            "required": [
              "fdi",
              "site",
              "value"
            ]
          },
          "idempotent": true,
          "description": "Set bleeding on probing at a site.",
          "descriptionKey": "ui.agent.periodontalChart.actions.toggleBleeding"
        },
        {
          "name": "toggle_plaque",
          "safety": "write",
          "argsType": "{ fdi: string; site: PeriodontalSiteId; value: boolean }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "fdi": {
                "type": "string",
                "description": "FDI tooth id ('11'–'48' permanent, '51'–'85' primary)."
              },
              "site": {
                "enum": [
                  "db",
                  "b",
                  "mb",
                  "dl",
                  "l",
                  "ml"
                ],
                "description": "Probing site: (m/d)b = mesio-/disto-/mid buccal, (m/d)l = mesio-/disto-/mid lingual."
              },
              "value": {
                "type": "boolean"
              }
            },
            "required": [
              "fdi",
              "site",
              "value"
            ]
          },
          "idempotent": true,
          "description": "Set plaque presence at a site.",
          "descriptionKey": "ui.agent.periodontalChart.actions.togglePlaque"
        },
        {
          "name": "set_mobility",
          "safety": "write",
          "argsType": "{ fdi: string; grade: 0 | 1 | 2 | 3 }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "fdi": {
                "type": "string",
                "description": "FDI tooth id ('11'–'48' permanent, '51'–'85' primary)."
              },
              "grade": {
                "enum": [
                  0,
                  1,
                  2,
                  3
                ]
              }
            },
            "required": [
              "fdi",
              "grade"
            ]
          },
          "idempotent": true,
          "description": "Set a tooth’s Miller mobility grade (0–3).",
          "descriptionKey": "ui.agent.periodontalChart.actions.setMobility"
        },
        {
          "name": "set_missing",
          "safety": "write",
          "argsType": "{ fdi: string; value: boolean }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "fdi": {
                "type": "string",
                "description": "FDI tooth id ('11'–'48' permanent, '51'–'85' primary)."
              },
              "value": {
                "type": "boolean"
              }
            },
            "required": [
              "fdi",
              "value"
            ]
          },
          "idempotent": true,
          "description": "Flag a tooth present or absent.",
          "descriptionKey": "ui.agent.periodontalChart.actions.setMissing"
        },
        {
          "name": "clear_tooth",
          "safety": "destructive",
          "argsType": "{ fdi: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "fdi": {
                "type": "string",
                "description": "FDI tooth id ('11'–'48' permanent, '51'–'85' primary)."
              }
            },
            "required": [
              "fdi"
            ]
          },
          "idempotent": true,
          "description": "Clear every reading from a tooth.",
          "descriptionKey": "ui.agent.periodontalChart.actions.clearTooth"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "periodontal-chart",
          "description": "Marks the PeriodontalChart root group."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        },
        "item": {
          "attr": "data-fdi",
          "description": "Each tooth column header carries its FDI id as `data-fdi`. Every measurement input also carries `data-fdi` + `data-site` + `data-field`. The root `data-mode` exposes interactive vs display."
        }
      }
    },
    {
      "kind": "component",
      "id": "periodontal-chart-card",
      "capabilities": [],
      "state": [
        {
          "name": "toothIds",
          "type": "string[]",
          "description": "FDI ids of the teeth currently charted. Tooth identifiers only — no patient identity.",
          "descriptionKey": "ui.agent.periodontalChartCard.state.toothIds"
        },
        {
          "name": "siteCount",
          "type": "number",
          "description": "Total number of probing sites rendered.",
          "descriptionKey": "ui.agent.periodontalChartCard.state.siteCount"
        },
        {
          "name": "deepPocketCount",
          "type": "number",
          "description": "Number of sites with a probing depth at or above the 6mm severe threshold.",
          "descriptionKey": "ui.agent.periodontalChartCard.state.deepPocketCount"
        }
      ],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "periodontal-chart-card",
          "description": "Marks the PeriodontalChartCard root region."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "periodontal-diagnosis",
      "capabilities": [
        "set_value"
      ],
      "state": [
        {
          "name": "diagnosis",
          "type": "object",
          "description": "Recorded stage (1–4), grade (A–C), extent, and ticked contributing-factor ids. The free-text note is never included.",
          "descriptionKey": "ui.agent.periodontalDiagnosis.state.diagnosis"
        },
        {
          "name": "summary",
          "type": "string",
          "description": "The composed, localised diagnosis sentence (e.g. \"Periodontitis — Stage III · Grade B · generalised\").",
          "descriptionKey": "ui.agent.periodontalDiagnosis.state.summary"
        },
        {
          "name": "complete",
          "type": "boolean",
          "description": "True once both a stage and a grade are recorded.",
          "descriptionKey": "ui.agent.periodontalDiagnosis.state.complete"
        }
      ],
      "actions": [
        {
          "name": "get_diagnosis",
          "safety": "read",
          "argsType": "{}",
          "argsSchema": {
            "type": "object",
            "properties": {}
          },
          "returns": "object",
          "returnsSchema": {
            "type": "object"
          },
          "idempotent": true,
          "description": "Read the recorded stage / grade / extent / factors. The note is never returned.",
          "descriptionKey": "ui.agent.periodontalDiagnosis.actions.getDiagnosis"
        },
        {
          "name": "set_stage",
          "safety": "write",
          "argsType": "{ stage: 1 | 2 | 3 | 4 }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "stage": {
                "enum": [
                  1,
                  2,
                  3,
                  4
                ],
                "description": "Periodontitis stage I–IV, as the integers 1–4."
              }
            },
            "required": [
              "stage"
            ]
          },
          "idempotent": true,
          "description": "Record the periodontitis stage (I–IV).",
          "descriptionKey": "ui.agent.periodontalDiagnosis.actions.setStage"
        },
        {
          "name": "set_grade",
          "safety": "write",
          "argsType": "{ grade: 'A' | 'B' | 'C' }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "grade": {
                "enum": [
                  "A",
                  "B",
                  "C"
                ],
                "description": "Periodontitis grade A–C (rate of progression)."
              }
            },
            "required": [
              "grade"
            ]
          },
          "idempotent": true,
          "description": "Record the periodontitis grade (A–C).",
          "descriptionKey": "ui.agent.periodontalDiagnosis.actions.setGrade"
        },
        {
          "name": "set_extent",
          "safety": "write",
          "argsType": "{ extent: 'localised' | 'generalised' | 'molarIncisor' }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "extent": {
                "enum": [
                  "localised",
                  "generalised",
                  "molarIncisor"
                ],
                "description": "Distribution: localised (<30%), generalised (≥30%), or molar-incisor."
              }
            },
            "required": [
              "extent"
            ]
          },
          "idempotent": true,
          "description": "Record the distribution / extent.",
          "descriptionKey": "ui.agent.periodontalDiagnosis.actions.setExtent"
        },
        {
          "name": "toggle_factor",
          "safety": "write",
          "argsType": "{ id: string; value: boolean }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "Contributing-factor id."
              },
              "value": {
                "type": "boolean"
              }
            },
            "required": [
              "id",
              "value"
            ]
          },
          "idempotent": true,
          "description": "Tick or clear a contributing factor.",
          "descriptionKey": "ui.agent.periodontalDiagnosis.actions.toggleFactor"
        },
        {
          "name": "clear_diagnosis",
          "safety": "destructive",
          "argsType": "{}",
          "argsSchema": {
            "type": "object",
            "properties": {}
          },
          "idempotent": true,
          "description": "Reset the whole diagnosis to empty.",
          "descriptionKey": "ui.agent.periodontalDiagnosis.actions.clearDiagnosis"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "periodontal-diagnosis",
          "description": "Marks the PeriodontalDiagnosis root group."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "periodontal-risk-chart",
      "capabilities": [],
      "state": [
        {
          "name": "overall",
          "type": "string",
          "description": "Overall periodontal risk verdict — \"low\" | \"moderate\" | \"high\". Aggregate only.",
          "descriptionKey": "ui.agent.periodontalRiskChart.state.overall"
        },
        {
          "name": "factorLevels",
          "type": "object",
          "description": "Per-factor risk levels keyed by factor (bleeding, pockets, toothLoss, boneLossAge, smoking, systemic) — each \"low\" | \"moderate\" | \"high\". No raw values.",
          "descriptionKey": "ui.agent.periodontalRiskChart.state.factorLevels"
        }
      ],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "periodontal-risk-chart",
          "description": "Marks the PeriodontalRiskChart root region."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "permission-matrix",
      "capabilities": [
        "select_multiple"
      ],
      "state": [
        {
          "name": "selection",
          "type": "string[]",
          "description": "Ids of currently-granted editable permissions. Locked owner permissions are excluded.",
          "descriptionKey": "ui.agent.permissionMatrix.state.selection"
        }
      ],
      "actions": [
        {
          "name": "set_selection",
          "safety": "write",
          "argsType": "{ values: string[] }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "values": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            },
            "required": [
              "values"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "values": [
                  "patients.view",
                  "billing.view"
                ]
              },
              "note": "Grant exactly the view permissions for patients and billing."
            }
          ],
          "description": "Replace the granted permissions with the given ids. Locked and unknown ids are ignored.",
          "descriptionKey": "ui.agent.permissionMatrix.actions.setSelection"
        },
        {
          "name": "clear",
          "safety": "destructive",
          "idempotent": true,
          "description": "Revoke every editable permission. Locked owner permissions are unaffected.",
          "descriptionKey": "ui.agent.permissionMatrix.actions.clear"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "permission-matrix",
          "description": "Marks the PermissionMatrix root group."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "phone-input",
      "capabilities": [
        "set_value"
      ],
      "state": [
        {
          "name": "value",
          "type": "string",
          "description": "Current E.164 phone number, or empty string when not yet valid.",
          "descriptionKey": "ui.agent.phoneInput.state.value"
        },
        {
          "name": "isEmpty",
          "type": "boolean",
          "description": "Whether the input has no value.",
          "descriptionKey": "ui.agent.phoneInput.state.isEmpty"
        }
      ],
      "actions": [
        {
          "name": "set_value",
          "safety": "write",
          "argsType": "{ value: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "value": {
                "type": "string",
                "description": "Phone number in E.164 or national format; the parser infers the country."
              }
            },
            "required": [
              "value"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "value": "+393331234567"
              },
              "note": "Set an Italian mobile."
            }
          ],
          "description": "Replace the phone number (E.164 or national format; parser will infer country).",
          "descriptionKey": "ui.agent.phoneInput.actions.setValue"
        },
        {
          "name": "clear",
          "safety": "destructive",
          "idempotent": true,
          "description": "Empty the input. Loses any typed value.",
          "descriptionKey": "ui.agent.phoneInput.actions.clear"
        },
        {
          "name": "focus",
          "safety": "read",
          "description": "Move keyboard focus to the phone-number input.",
          "descriptionKey": "ui.agent.phoneInput.actions.focus"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "phone-input",
          "description": "Marks the PhoneInput wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "popover",
      "capabilities": [
        "open",
        "close"
      ],
      "state": [
        {
          "name": "isOpen",
          "type": "boolean",
          "description": "True when the popover is currently open.",
          "descriptionKey": "ui.agent.popover.state.isOpen"
        }
      ],
      "actions": [
        {
          "name": "open",
          "safety": "read",
          "idempotent": true,
          "description": "Open the popover.",
          "descriptionKey": "ui.agent.popover.actions.open"
        },
        {
          "name": "close",
          "safety": "read",
          "idempotent": true,
          "description": "Close the popover.",
          "descriptionKey": "ui.agent.popover.actions.close"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "popover"
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop on Popover.Root."
        }
      }
    },
    {
      "kind": "component",
      "id": "position-grid",
      "capabilities": [
        "select_single"
      ],
      "state": [
        {
          "name": "value",
          "type": "string",
          "description": "Currently selected position value (e.g. \"top-start\"), or empty string when none.",
          "descriptionKey": "ui.agent.positionGrid.state.value"
        }
      ],
      "actions": [
        {
          "name": "set_value",
          "safety": "write",
          "argsType": "{ value: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "value": {
                "type": "string"
              }
            },
            "required": [
              "value"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "value": "center"
              },
              "note": "Selects the centre cell of the default 3×3 grid."
            }
          ],
          "description": "Select the cell with the given position value.",
          "descriptionKey": "ui.agent.positionGrid.actions.setValue"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "position-grid",
          "description": "Marks the PositionGrid root."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        },
        "item": {
          "attr": "data-option-id",
          "description": "Position value emitted on each rendered cell."
        }
      }
    },
    {
      "kind": "component",
      "id": "postal-code-input",
      "capabilities": [
        "set_value"
      ],
      "state": [
        {
          "name": "value",
          "type": "string",
          "description": "Current postal code value.",
          "descriptionKey": "ui.agent.postalCodeInput.state.value"
        },
        {
          "name": "isEmpty",
          "type": "boolean",
          "description": "Whether the field has no value.",
          "descriptionKey": "ui.agent.postalCodeInput.state.isEmpty"
        }
      ],
      "actions": [
        {
          "name": "set_value",
          "safety": "write",
          "argsType": "{ value: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "value": {
                "type": "string"
              }
            },
            "required": [
              "value"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "value": "20121"
              },
              "note": "An Italian CAP."
            }
          ],
          "description": "Replace the postal code value.",
          "descriptionKey": "ui.agent.postalCodeInput.actions.setValue"
        },
        {
          "name": "clear",
          "safety": "destructive",
          "idempotent": true,
          "description": "Empty the field. Loses any typed value.",
          "descriptionKey": "ui.agent.postalCodeInput.actions.clear"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "postal-code-input"
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "practice-profile-hero",
      "capabilities": [],
      "state": [
        {
          "name": "name",
          "type": "string",
          "description": "Practice display name currently rendered.",
          "descriptionKey": "ui.agent.practiceProfileHero.state.name"
        },
        {
          "name": "hasCover",
          "type": "boolean",
          "description": "Whether a cover-image strip is rendered. Structural flag only — never the image URL or any PHI.",
          "descriptionKey": "ui.agent.practiceProfileHero.state.hasCover"
        }
      ],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "practice-profile-hero",
          "description": "Marks the PracticeProfileHero root region."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "practice-results",
      "capabilities": [
        "scroll",
        "pick"
      ],
      "state": [
        {
          "name": "variant",
          "type": "string",
          "description": "Active variant — one of `split-list-map`, `map-first`, `rich-cards`.",
          "descriptionKey": "ui.agent.practiceResults.state.variant"
        }
      ],
      "actions": [
        {
          "name": "scroll_to_result",
          "safety": "read",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "Stable result id (the data-result-id of the card)."
              }
            },
            "required": [
              "id"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "id": "practice-42"
              },
              "note": "Scroll to a specific result."
            }
          ],
          "description": "Scroll the result card with the given id into the visible viewport.",
          "descriptionKey": "ui.agent.practiceResults.actions.scrollToResult"
        },
        {
          "name": "focus_pin",
          "safety": "read",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "Stable result id whose map pin to highlight."
              }
            },
            "required": [
              "id"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "id": "practice-42"
              },
              "note": "Highlight the matching pin."
            }
          ],
          "description": "Highlight the map pin for the given result id (no-op on rich-cards).",
          "descriptionKey": "ui.agent.practiceResults.actions.focusPin"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "practice-results",
          "description": "Marks the PracticeResults root region. The headingLevel prop accepts 1 to 6 (default 2) for the optional results heading; use 1 when it is the page title. Card names and default error and empty-state titles use the next level, capped at 6."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        },
        "item": {
          "attr": "data-result-id",
          "description": "Stable result id emitted on each rendered result card. Used by scroll_to_result / focus_pin to address a single result. The non-focusable card group is labelled by the practice-result-{id}-name heading, which contains data-component=\"practice-result-name-link\": a visible link to result.href that navigates without firing onResultSelect or click telemetry. Each card also carries up to two CTA anchors: data-component=\"practice-result-open-cta\" (practice page; absent when the consumer sets showCardOpenButton=false) and data-component=\"practice-result-book-cta\" (booking flow; data-slot-aware=\"true\" when it deep-links to a next slot). Card content carries its own read-only hooks: data-component=\"practice-result-tagline\", data-component=\"practice-result-description\", and data-component=\"practice-result-price\" (the kit-formatted first-visit cost: firstVisitPrice supports fixed, from and range amounts plus an optional practice-written label; it takes precedence over the older firstVisitPriceCents fixed-price field. Absent when neither price is set)."
        }
      }
    },
    {
      "kind": "component",
      "id": "pregnancy-dating",
      "capabilities": [
        "set_value"
      ],
      "state": [
        {
          "name": "inputs",
          "type": "{ method: string, referenceDate: string | null, cycleLength: number | null, embryoAge: 3 | 5, crlMm: number | null, scanDate: string | null, datingAdjustment: number | null, asOfDate: string }",
          "description": "The dating inputs as entered — anchor method, its reference date, cycle length (LMP), embryo age (IVF), the optional CRL + scan date, the manual ±days nudge, and the evaluation date. Dates are `yyyy-MM-dd`. Read this to see which method a reference date will be interpreted under.",
          "descriptionKey": "ui.agent.pregnancyDating.state.inputs"
        },
        {
          "name": "result",
          "type": "{ dueDate: string, gestationalStart: string, gestationalAge: { weeks: number, days: number, totalDays: number } | null, trimester: string } | null",
          "description": "Computed estimated delivery date, the GA day-0 anchor after any re-dating or adjustment, the gestational age in completed weeks + days as of the evaluation date, and the trimester band (preconception / first / second / third / postterm). Null until a reference date is set.",
          "descriptionKey": "ui.agent.pregnancyDating.state.result"
        }
      ],
      "actions": [
        {
          "name": "set_method",
          "safety": "write",
          "argsType": "{ method: 'lmp' | 'conception' | 'ivf' | 'edd' }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "method": {
                "enum": [
                  "lmp",
                  "conception",
                  "ivf",
                  "edd"
                ],
                "description": "Which anchor to date from — last menstrual period, conception, IVF transfer, or a known estimated delivery date."
              }
            },
            "required": [
              "method"
            ],
            "additionalProperties": false
          },
          "returns": "boolean",
          "returnsSchema": {
            "type": "boolean",
            "description": "True when the method was applied."
          },
          "idempotent": true,
          "errors": [
            "Returns false for a method outside the four supported anchors."
          ],
          "examples": [
            {
              "args": {
                "method": "edd"
              },
              "note": "Date backwards from a known EDD."
            }
          ],
          "description": "Choose which anchor the pregnancy is dated from. The reference date is kept and re-interpreted under the new method, so set the method first — only a known EDD may be in the future.",
          "descriptionKey": "ui.agent.pregnancyDating.actions.setMethod"
        },
        {
          "name": "set_reference_date",
          "safety": "write",
          "argsType": "{ date: string | null }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "date": {
                "oneOf": [
                  {
                    "type": "string",
                    "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                    "description": "Local calendar date, `yyyy-MM-dd`."
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "The date the active method anchors on — LMP, conception, transfer, or known EDD — or null to clear it. Only a known EDD may be in the future."
              }
            },
            "required": [
              "date"
            ],
            "additionalProperties": false
          },
          "returns": "boolean",
          "returnsSchema": {
            "type": "boolean",
            "description": "True when the date was applied."
          },
          "idempotent": true,
          "errors": [
            "Returns false for an unparseable date, or for a future date under any method but `edd` — the on-screen DatePicker caps those at today."
          ],
          "examples": [
            {
              "args": {
                "date": "2026-01-12"
              },
              "note": "Under the default LMP method, a last period starting 12 January."
            }
          ],
          "description": "Set the reference date for the active method. This is the only required input — the result stays null without it.",
          "descriptionKey": "ui.agent.pregnancyDating.actions.setReferenceDate"
        },
        {
          "name": "set_cycle_length",
          "safety": "write",
          "argsType": "{ days: number | null }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "days": {
                "oneOf": [
                  {
                    "type": "integer",
                    "minimum": 20,
                    "maximum": 45
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Average cycle length in days (20–45), or null to fall back to the 28-day default."
              }
            },
            "required": [
              "days"
            ],
            "additionalProperties": false
          },
          "returns": "boolean",
          "returnsSchema": {
            "type": "boolean",
            "description": "True when the value was applied."
          },
          "idempotent": true,
          "errors": [
            "Returns false outside 20–45 days — the same bounds the on-screen NumberInput enforces.",
            "Applies but changes nothing unless the method is `lmp`, and is ignored once a CRL re-dating is confirmed."
          ],
          "description": "LMP method only — set the average cycle length, which shifts Naegele dating off the 28-day assumption.",
          "descriptionKey": "ui.agent.pregnancyDating.actions.setCycleLength"
        },
        {
          "name": "set_embryo_age",
          "safety": "write",
          "argsType": "{ days: 3 | 5 }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "days": {
                "enum": [
                  3,
                  5
                ],
                "description": "Embryo age at transfer in days — 3 (cleavage) or 5 (blastocyst)."
              }
            },
            "required": [
              "days"
            ],
            "additionalProperties": false
          },
          "returns": "boolean",
          "returnsSchema": {
            "type": "boolean",
            "description": "True when the value was applied."
          },
          "idempotent": true,
          "errors": [
            "Returns false for any value other than 3 or 5.",
            "Applies but changes nothing unless the method is `ivf`."
          ],
          "description": "IVF method only — set the embryo age at transfer, which offsets the transfer date back to a notional LMP.",
          "descriptionKey": "ui.agent.pregnancyDating.actions.setEmbryoAge"
        },
        {
          "name": "set_crl",
          "safety": "write",
          "argsType": "{ crlMm?: number | null, scanDate?: string | null }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "crlMm": {
                "oneOf": [
                  {
                    "type": "number",
                    "exclusiveMinimum": 0
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Crown-rump length in millimetres, or null to clear it."
              },
              "scanDate": {
                "oneOf": [
                  {
                    "type": "string",
                    "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Date of the CRL scan (`yyyy-MM-dd`, not in the future), or null to clear it."
              }
            },
            "additionalProperties": false
          },
          "returns": "boolean",
          "returnsSchema": {
            "type": "boolean",
            "description": "True when the measurement was applied."
          },
          "idempotent": true,
          "errors": [
            "Returns false and writes nothing when the length is not positive or the scan date is unparseable or in the future — the payload applies all-or-nothing.",
            "Re-dating only happens under the `lmp` method, and only when both the length and the scan date are set."
          ],
          "examples": [
            {
              "args": {
                "crlMm": 42,
                "scanDate": "2026-02-20"
              },
              "note": "A first-trimester CRL that may re-date the pregnancy per ACOG CO 700."
            }
          ],
          "description": "LMP method only — set the first-trimester crown-rump length and its scan date. A confirmed re-dating wins over both the cycle length and the manual adjustment.",
          "descriptionKey": "ui.agent.pregnancyDating.actions.setCrl"
        },
        {
          "name": "set_dating_adjustment",
          "safety": "write",
          "argsType": "{ days: number | null }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "days": {
                "oneOf": [
                  {
                    "type": "integer"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Whole days to nudge the dating by — positive moves the pregnancy further along — or null for no adjustment."
              }
            },
            "required": [
              "days"
            ],
            "additionalProperties": false
          },
          "returns": "boolean",
          "returnsSchema": {
            "type": "boolean",
            "description": "True when the value was applied."
          },
          "idempotent": true,
          "errors": [
            "Returns false for a non-integer number of days.",
            "Applies but changes nothing while a CRL re-dating is confirmed — the measurement wins."
          ],
          "examples": [
            {
              "args": {
                "days": 3
              },
              "note": "An uncertain LMP judged three days earlier than entered."
            }
          ],
          "description": "Nudge the dating by whole days for an uncertain anchor. Positive moves the pregnancy further along (earlier effective LMP, earlier due date).",
          "descriptionKey": "ui.agent.pregnancyDating.actions.setDatingAdjustment"
        },
        {
          "name": "set_as_of_date",
          "safety": "write",
          "argsType": "{ date: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "date": {
                "type": "string",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                "description": "Date to evaluate gestational age and trimester against, `yyyy-MM-dd`. May be in the future to project forward."
              }
            },
            "required": [
              "date"
            ],
            "additionalProperties": false
          },
          "returns": "boolean",
          "returnsSchema": {
            "type": "boolean",
            "description": "True when the date was applied."
          },
          "idempotent": true,
          "errors": [
            "Returns false for an unparseable date."
          ],
          "examples": [
            {
              "args": {
                "date": "2026-09-15"
              },
              "note": "Project gestational age forward to an upcoming appointment."
            }
          ],
          "description": "Set the date gestational age, trimester and the antenatal schedule are evaluated against. Defaults to today; the estimated delivery date itself does not depend on it.",
          "descriptionKey": "ui.agent.pregnancyDating.actions.setAsOfDate"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "pregnancy-dating",
          "description": "Marks the PregnancyDating wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop. Also the registry key — without an `id` the instance does not register and the handle-driven actions/state are unreachable."
        }
      }
    },
    {
      "kind": "component",
      "id": "pregnancy-weight-gain",
      "capabilities": [
        "set_value"
      ],
      "state": [
        {
          "name": "inputs",
          "type": "{ heightCm: number | null, prePregnancyKg: number | null, currentKg: number | null, gestationalWeeks: number | null }",
          "description": "The four entered measurements — height (cm), pre-pregnancy weight (kg), current weight (kg) and completed gestational weeks. Null for anything not yet entered.",
          "descriptionKey": "ui.agent.pregnancyWeightGain.state.inputs"
        },
        {
          "name": "plurality",
          "type": "'singleton' | 'twin' | 'triplet'",
          "description": "Number of babies the assessment is keyed to. Drives which IOM band applies — twins use the higher twin bands, triplets have no published band.",
          "descriptionKey": "ui.agent.pregnancyWeightGain.state.plurality"
        },
        {
          "name": "result",
          "type": "{ category: string, plurality: string, actualGainKg: number, status: string | null, recommendedToDate: { min: number, max: number } | null, totalRange: { min: number, max: number } | null, weeklyRate: number | null, rateStatus: string | null } | null",
          "description": "Computed assessment — actual gain (kg), the IOM recommended-to-date and total bands, and where the gain sits against them (below / within / above). Null until every input is valid; the bands are null when the IOM publishes none (triplets, underweight twins).",
          "descriptionKey": "ui.agent.pregnancyWeightGain.state.result"
        }
      ],
      "actions": [
        {
          "name": "set_value",
          "safety": "write",
          "argsType": "{ heightCm?: number | null, prePregnancyKg?: number | null, currentKg?: number | null, gestationalWeeks?: number | null }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "heightCm": {
                "type": [
                  "number",
                  "null"
                ],
                "minimum": 0,
                "description": "Height in centimetres."
              },
              "prePregnancyKg": {
                "type": [
                  "number",
                  "null"
                ],
                "minimum": 0,
                "description": "Pre-pregnancy weight in kilograms."
              },
              "currentKg": {
                "type": [
                  "number",
                  "null"
                ],
                "minimum": 0,
                "description": "Current weight in kilograms."
              },
              "gestationalWeeks": {
                "type": [
                  "number",
                  "null"
                ],
                "minimum": 0,
                "maximum": 42,
                "description": "Completed gestational weeks."
              }
            },
            "additionalProperties": false
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "heightCm": 165,
                "prePregnancyKg": 60,
                "currentKg": 72,
                "gestationalWeeks": 30
              },
              "note": "165 cm, 60 → 72 kg at 30 weeks → +12 kg against the normal-BMI band."
            }
          ],
          "description": "Set one or more of the four measurements. Omitted fields are left unchanged; the assessment recomputes as soon as all four are valid.",
          "descriptionKey": "ui.agent.pregnancyWeightGain.actions.setValue"
        },
        {
          "name": "set_plurality",
          "safety": "write",
          "argsType": "{ plurality: 'singleton' | 'twin' | 'triplet' }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "plurality": {
                "enum": [
                  "singleton",
                  "twin",
                  "triplet"
                ],
                "description": "Number of babies to assess against."
              }
            },
            "required": [
              "plurality"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "plurality": "twin"
              },
              "note": "Assess against the twin bands."
            }
          ],
          "description": "Choose the number of babies. Twins use the higher IOM twin bands; triplets have no published IOM range, so only the actual gain is reported.",
          "descriptionKey": "ui.agent.pregnancyWeightGain.actions.setPlurality"
        },
        {
          "name": "reset",
          "safety": "destructive",
          "idempotent": true,
          "description": "Clear the four measurements and the computed assessment. The plurality choice is a setting and is kept.",
          "descriptionKey": "ui.agent.pregnancyWeightGain.actions.reset"
        },
        {
          "name": "get_result",
          "safety": "read",
          "returns": "{ actualGainKg: number, status: string | null, … } | null",
          "returnsSchema": {
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "category": {
                    "enum": [
                      "underweight",
                      "normal",
                      "overweight",
                      "obese"
                    ]
                  },
                  "plurality": {
                    "enum": [
                      "singleton",
                      "twin",
                      "triplet"
                    ]
                  },
                  "actualGainKg": {
                    "type": "number"
                  },
                  "status": {
                    "oneOf": [
                      {
                        "enum": [
                          "below",
                          "within",
                          "above"
                        ]
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "recommendedToDate": {
                    "oneOf": [
                      {
                        "type": "object",
                        "properties": {
                          "min": {
                            "type": "number"
                          },
                          "max": {
                            "type": "number"
                          }
                        },
                        "required": [
                          "min",
                          "max"
                        ]
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "totalRange": {
                    "oneOf": [
                      {
                        "type": "object",
                        "properties": {
                          "min": {
                            "type": "number"
                          },
                          "max": {
                            "type": "number"
                          }
                        },
                        "required": [
                          "min",
                          "max"
                        ]
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "weeklyRate": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "rateStatus": {
                    "oneOf": [
                      {
                        "enum": [
                          "below",
                          "within",
                          "above"
                        ]
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "required": [
                  "category",
                  "actualGainKg"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "idempotent": true,
          "description": "Read back the computed assessment — the same value the `result` state slot returns. Null until every input is valid.",
          "descriptionKey": "ui.agent.pregnancyWeightGain.actions.getResult"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "pregnancy-weight-gain",
          "description": "Marks the PregnancyWeightGain calculator wrapper. The themed DOM carries the computed result card; an SR-only live region announces the actual gain and status."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the `id` prop, and also the registry key — without an `id` the instance does not register and the handle-driven actions are unreachable."
        }
      }
    },
    {
      "kind": "component",
      "id": "privacy-lock",
      "capabilities": [
        "open",
        "dismiss"
      ],
      "state": [
        {
          "name": "isLocked",
          "type": "boolean",
          "description": "True when the privacy overlay is open.",
          "descriptionKey": "ui.agent.privacyLock.state.isLocked"
        }
      ],
      "actions": [
        {
          "name": "lock",
          "safety": "read",
          "idempotent": true,
          "description": "Open the privacy overlay.",
          "descriptionKey": "ui.agent.privacyLock.actions.lock"
        },
        {
          "name": "unlock",
          "safety": "read",
          "idempotent": true,
          "description": "Close the privacy overlay (consumer-confirmed action).",
          "descriptionKey": "ui.agent.privacyLock.actions.unlock"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "privacy-lock",
          "description": "Marks the PrivacyLock trigger."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "product-hub-panel",
      "capabilities": [
        "pick"
      ],
      "state": [
        {
          "name": "items",
          "type": "Array<{ id: string; unseen: boolean }>",
          "description": "Currently-displayed releases. Ids + unseen flag only — no content.",
          "descriptionKey": "ui.agent.productHubPanel.state.items"
        },
        {
          "name": "unseenCount",
          "type": "number",
          "description": "Number of displayed releases still marked unseen.",
          "descriptionKey": "ui.agent.productHubPanel.state.unseenCount"
        }
      ],
      "actions": [
        {
          "name": "select_item",
          "safety": "read",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "Stable release id (the data-update-id of the row)."
              }
            },
            "required": [
              "id"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "id": "rel-0680"
              },
              "note": "Activate a specific release row."
            }
          ],
          "description": "Activate the release with the given id (fires the host analytics hook).",
          "descriptionKey": "ui.agent.productHubPanel.actions.selectItem"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "product-hub-panel",
          "description": "Marks the ProductHubPanel section."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop. Required to address a specific panel from the agent."
        },
        "item": {
          "attr": "data-update-id",
          "description": "Stable release id emitted on each rendered release row inside the panel."
        }
      }
    },
    {
      "kind": "component",
      "id": "product-hub-tray",
      "capabilities": [
        "open",
        "close"
      ],
      "state": [
        {
          "name": "unseenCount",
          "type": "number",
          "description": "Number of unseen product releases — the trigger badge count.",
          "descriptionKey": "ui.agent.productHubTray.state.unseenCount"
        }
      ],
      "actions": [
        {
          "name": "open",
          "safety": "read",
          "idempotent": true,
          "description": "Open the product-updates panel.",
          "descriptionKey": "ui.agent.productHubTray.actions.open"
        },
        {
          "name": "close",
          "safety": "read",
          "idempotent": true,
          "description": "Close the product-updates panel.",
          "descriptionKey": "ui.agent.productHubTray.actions.close"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "product-hub-tray",
          "description": "Marks the ProductHubTray wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop. Required to address a specific tray from the agent."
        },
        "item": {
          "attr": "data-update-id",
          "description": "Stable release id emitted on each rendered release row inside the tray."
        }
      }
    },
    {
      "kind": "component",
      "id": "progress",
      "capabilities": [
        "set_value"
      ],
      "state": [
        {
          "name": "value",
          "type": "number | null",
          "description": "The figure the bar currently shows, in the same units as the `max` prop (default max 100) — including a value written imperatively by `set_value`. Null while indeterminate.",
          "descriptionKey": "ui.agent.progress.state.value"
        },
        {
          "name": "indeterminate",
          "type": "boolean",
          "description": "True when the operation reports no measurable progress. Read this before treating a null/0 `value` as \"nothing done yet\" — the two are different states.",
          "descriptionKey": "ui.agent.progress.state.indeterminate"
        }
      ],
      "actions": [
        {
          "name": "set_value",
          "safety": "write",
          "argsType": "{ value: number }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "value": {
                "type": "number",
                "minimum": 0,
                "description": "Progress figure in the same units as the `max` prop (default max 100). Clamped to [0, max]."
              }
            },
            "required": [
              "value"
            ],
            "additionalProperties": false
          },
          "idempotent": true,
          "errors": [
            "Has no visible effect on an indeterminate instance — the animated fill ignores the painted value. Check the `indeterminate` state slot first.",
            "Overwritten by the next React render that changes the `value` prop."
          ],
          "examples": [
            {
              "args": {
                "value": 80
              },
              "note": "Paint the bar at 80% of a default max."
            }
          ],
          "description": "Paint the displayed progress value straight onto the DOM, bypassing React. Read it back with the `value` state slot — the `value` prop does not change.",
          "descriptionKey": "ui.agent.progress.actions.setValue"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "progress"
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop. Also the registry key — without an `id` the instance does not register and the handle-driven action/state are unreachable."
        }
      }
    },
    {
      "kind": "component",
      "id": "progress-notice",
      "capabilities": [
        "expand",
        "dismiss"
      ],
      "state": [
        {
          "name": "value",
          "type": "number",
          "description": "Progress so far, in the units of max.",
          "descriptionKey": "ui.agent.progressNotice.state.value"
        },
        {
          "name": "max",
          "type": "number",
          "description": "The value at which the import is done.",
          "descriptionKey": "ui.agent.progressNotice.state.max"
        },
        {
          "name": "complete",
          "type": "boolean",
          "description": "True once every item is ready or the value has reached max.",
          "descriptionKey": "ui.agent.progressNotice.state.complete"
        },
        {
          "name": "readyCount",
          "type": "number",
          "description": "How many items in the details list are ready.",
          "descriptionKey": "ui.agent.progressNotice.state.readyCount"
        },
        {
          "name": "itemCount",
          "type": "number",
          "description": "How many items the details list has (0: no list).",
          "descriptionKey": "ui.agent.progressNotice.state.itemCount"
        },
        {
          "name": "detailsOpen",
          "type": "boolean",
          "description": "Whether the details list is open.",
          "descriptionKey": "ui.agent.progressNotice.state.detailsOpen"
        }
      ],
      "actions": [
        {
          "name": "set_details_open",
          "safety": "read",
          "argsType": "open",
          "argsSchema": {
            "type": "object",
            "properties": {
              "open": {
                "type": "boolean",
                "description": "True to open the details list, false to close it."
              }
            },
            "required": [
              "open"
            ]
          },
          "returns": "boolean (applied)",
          "returnsSchema": {
            "type": "boolean",
            "description": "True when applied; false when the notice has no list."
          },
          "idempotent": true,
          "errors": [
            "No details list (itemCount is 0): returns false."
          ],
          "description": "Open or close the details list of the import.",
          "descriptionKey": "ui.agent.progressNotice.actions.setDetailsOpen"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "progress-notice",
          "description": "Marks the ProgressNotice. Also carries data-complete=\"true\" once the import is complete. The notice inside is a kit Alert; its close control is [data-alert-dismiss]."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        },
        "item": {
          "attr": "data-item-id",
          "sourceProp": "items[].id",
          "description": "Each row of the details list, from ProgressNoticeItem.id. A ready row also carries data-ready=\"true\"."
        }
      }
    },
    {
      "kind": "component",
      "id": "province-select",
      "capabilities": [
        "select_single",
        "set_value"
      ],
      "state": [
        {
          "name": "value",
          "type": "string | null",
          "description": "Selected province code (UPPERCASED sigla for Italy), or null when nothing is selected.",
          "descriptionKey": "ui.agent.provinceSelect.state.value"
        }
      ],
      "actions": [
        {
          "name": "set_value",
          "safety": "write",
          "argsType": "{ value: string | null }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "value": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Province code to select (UPPERCASED), or null to clear."
              }
            },
            "required": [
              "value"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "value": "MI"
              },
              "note": "Select Milano."
            }
          ],
          "description": "Set the selected province by code.",
          "descriptionKey": "ui.agent.provinceSelect.actions.setValue"
        },
        {
          "name": "clear_selection",
          "safety": "destructive",
          "idempotent": true,
          "description": "Clear the selected province.",
          "descriptionKey": "ui.agent.provinceSelect.actions.clearSelection"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "province-select"
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        },
        "item": {
          "attr": "data-option-id",
          "description": "Each province option emits its code as data-option-id."
        }
      }
    },
    {
      "kind": "component",
      "id": "public-footer",
      "capabilities": [],
      "state": [
        {
          "name": "variant",
          "type": "string",
          "description": "Active variant — one of `minimal`, `compact`, `full`.",
          "descriptionKey": "ui.agent.publicFooter.state.variant"
        },
        {
          "name": "legalUrls",
          "type": "object",
          "description": "Resolved legal URLs for the active locale + marketingBaseUrl + overrides: `{ privacy, terms, contacts }`.",
          "descriptionKey": "ui.agent.publicFooter.state.legalUrls"
        }
      ],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "public-footer",
          "description": "Marks the PublicFooter root region. The root also carries `data-variant=\"minimal|compact|full\"` for CSS + agent selectors."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the `id` prop. Emitted alongside the plain `id` attribute (kept for in-page anchors)."
        }
      }
    },
    {
      "kind": "component",
      "id": "public-header",
      "capabilities": [
        "open",
        "close"
      ],
      "state": [
        {
          "name": "menuOpen",
          "type": "boolean",
          "description": "Whether the mobile drawer is currently open.",
          "descriptionKey": "ui.agent.publicHeader.state.menuOpen"
        }
      ],
      "actions": [
        {
          "name": "open_menu",
          "safety": "read",
          "idempotent": true,
          "description": "Open the mobile drawer.",
          "descriptionKey": "ui.agent.publicHeader.actions.openMenu"
        },
        {
          "name": "close_menu",
          "safety": "read",
          "idempotent": true,
          "description": "Close the mobile drawer.",
          "descriptionKey": "ui.agent.publicHeader.actions.closeMenu"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "public-header"
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop on PublicHeader."
        }
      }
    },
    {
      "kind": "component",
      "id": "qr-code",
      "capabilities": [],
      "state": [
        {
          "name": "value",
          "type": "string",
          "description": "The string (typically an https URL) encoded into the QR.",
          "descriptionKey": "ui.agent.qrCode.state.value"
        }
      ],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "qr-code",
          "description": "Marks the element as a kit QrCode renderer."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "radio",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "radio",
          "description": "Marks a single Radio item. Group-level selection is exposed by the parent RadioGroup adapter."
        }
      }
    },
    {
      "kind": "component",
      "id": "radio-group",
      "capabilities": [
        "select_single"
      ],
      "state": [
        {
          "name": "value",
          "type": "string",
          "description": "Currently selected radio value, or empty string when none.",
          "descriptionKey": "ui.agent.radioGroup.state.value"
        }
      ],
      "actions": [
        {
          "name": "set_value",
          "safety": "write",
          "argsType": "{ value: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "value": {
                "type": "string",
                "description": "Value of the radio to select (its data-option-id)."
              }
            },
            "required": [
              "value"
            ]
          },
          "idempotent": true,
          "description": "Select the radio with the given value. A value that matches no enabled radio is ignored.",
          "descriptionKey": "ui.agent.radioGroup.actions.setValue"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "radio-group",
          "description": "Marks the RadioGroup root."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        },
        "item": {
          "attr": "data-option-id",
          "description": "Stable opaque value emitted on each rendered Radio child."
        }
      }
    },
    {
      "kind": "component",
      "id": "radiograph-panel",
      "capabilities": [
        "pick",
        "view_change"
      ],
      "state": [
        {
          "name": "radiographs",
          "type": "Array<{ id: string; kind?: string }>",
          "description": "Structural references (id + kind) to the films shown for the selected tooth.",
          "descriptionKey": "ui.agent.radiographPanel.state.radiographs"
        }
      ],
      "actions": [
        {
          "name": "view_radiograph",
          "safety": "read",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              }
            },
            "required": [
              "id"
            ]
          },
          "idempotent": true,
          "description": "Open a film in the fullscreen viewer by id.",
          "descriptionKey": "ui.agent.radiographPanel.actions.viewRadiograph"
        },
        {
          "name": "close_viewer",
          "safety": "read",
          "idempotent": true,
          "description": "Close the fullscreen radiograph viewer.",
          "descriptionKey": "ui.agent.radiographPanel.actions.closeViewer"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "radiograph-panel"
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        },
        "item": {
          "attr": "data-radiograph-id",
          "description": "Each film row (`<li>`) carries its radiograph id as `data-radiograph-id`. The panel root additionally carries the selected tooth's FDI id as `data-tooth`."
        }
      }
    },
    {
      "kind": "component",
      "id": "rating",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "rating",
          "description": "Marks the element as a kit Rating."
        }
      }
    },
    {
      "kind": "component",
      "id": "recaptcha-widget",
      "capabilities": [
        "submit"
      ],
      "state": [
        {
          "name": "hasToken",
          "type": "boolean",
          "description": "True when the widget currently holds a valid verification token.",
          "descriptionKey": "ui.agent.recaptchaWidget.state.hasToken"
        }
      ],
      "actions": [
        {
          "name": "execute",
          "safety": "write",
          "openWorld": true,
          "description": "Programmatically trigger the captcha challenge. Issues a token via the callback.",
          "descriptionKey": "ui.agent.recaptchaWidget.actions.execute"
        },
        {
          "name": "reset",
          "safety": "destructive",
          "idempotent": true,
          "description": "Clear the current token and re-roll the captcha. Irreversible.",
          "descriptionKey": "ui.agent.recaptchaWidget.actions.reset"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "recaptcha-widget",
          "description": "Marks the RecaptchaWidget wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop (or the surrounding FormField id)."
        }
      }
    },
    {
      "kind": "component",
      "id": "resizable",
      "capabilities": [
        "set_value"
      ],
      "state": [
        {
          "name": "sizes",
          "type": "number[]",
          "description": "Current per-panel sizes as percentages of the group.",
          "descriptionKey": "ui.agent.resizable.state.sizes"
        }
      ],
      "actions": [
        {
          "name": "set_sizes",
          "safety": "write",
          "argsType": "{ sizes: number[] }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "sizes": {
                "type": "array",
                "items": {
                  "type": "number"
                },
                "description": "Per-panel sizes as percentages, summing to 100."
              }
            },
            "required": [
              "sizes"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "sizes": [
                  30,
                  70
                ]
              },
              "note": "Split a two-panel group 30/70."
            }
          ],
          "description": "Replace the panel sizes (percentages, summing to 100).",
          "descriptionKey": "ui.agent.resizable.actions.setSizes"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "resizable"
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop on PanelGroup."
        },
        "item": {
          "attr": "data-panel-id",
          "description": "Each Panel emits its `id` as data-panel-id."
        }
      }
    },
    {
      "kind": "component",
      "id": "reviews-panel",
      "capabilities": [
        "filter"
      ],
      "state": [
        {
          "name": "filter",
          "type": "string",
          "description": "Active star-bucket filter — `\"all\"` or an integer 1..5. Reads the controlled `filter` prop.",
          "descriptionKey": "ui.agent.reviewsPanel.state.filter"
        },
        {
          "name": "visibleCount",
          "type": "number",
          "description": "Number of reviews currently rendered after the filter is applied.",
          "descriptionKey": "ui.agent.reviewsPanel.state.visibleCount"
        }
      ],
      "actions": [
        {
          "name": "set_filter",
          "safety": "read",
          "argsType": "{ filter: \"all\" | 1 | 2 | 3 | 4 | 5 }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "filter": {
                "description": "Star bucket to show, or \"all\" to clear the filter.",
                "oneOf": [
                  {
                    "type": "string",
                    "enum": [
                      "all"
                    ]
                  },
                  {
                    "type": "integer",
                    "enum": [
                      1,
                      2,
                      3,
                      4,
                      5
                    ]
                  }
                ]
              }
            },
            "required": [
              "filter"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "filter": 5
              },
              "note": "Show only 5-star reviews."
            },
            {
              "args": {
                "filter": "all"
              },
              "note": "Clear the star filter."
            }
          ],
          "description": "Narrow the visible review list to a star bucket, or `\"all\"` to clear the filter.",
          "descriptionKey": "ui.agent.reviewsPanel.actions.setFilter"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "reviews-panel",
          "description": "Marks the ReviewsPanel root region."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "rich-text-editor",
      "capabilities": [
        "edit_inline"
      ],
      "state": [
        {
          "name": "html",
          "type": "string",
          "description": "Sanitised HTML representation of the editor content.",
          "descriptionKey": "ui.agent.richTextEditor.state.html"
        },
        {
          "name": "text",
          "type": "string",
          "description": "Plain-text content of the editor (tags stripped).",
          "descriptionKey": "ui.agent.richTextEditor.state.text"
        },
        {
          "name": "markdown",
          "type": "string",
          "description": "Markdown representation of the editor content. The Redactor engine has no native Markdown serialiser, so this is always empty — read `html` instead.",
          "descriptionKey": "ui.agent.richTextEditor.state.markdown"
        },
        {
          "name": "aiBusy",
          "type": "boolean",
          "description": "True while a one-shot AI action (a practice template, spelling or auto-format) is rewriting the note. Read `html` once it is false.",
          "descriptionKey": "ui.agent.richTextEditor.state.aiBusy"
        }
      ],
      "actions": [
        {
          "name": "set_content",
          "safety": "destructive",
          "argsType": "{ html: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "html": {
                "type": "string",
                "description": "Replacement HTML (sanitised via DOMPurify)."
              }
            },
            "required": [
              "html"
            ]
          },
          "idempotent": true,
          "description": "Replace the editor content. Loses unsaved input.",
          "descriptionKey": "ui.agent.richTextEditor.actions.setContent"
        },
        {
          "name": "insert_at_cursor",
          "safety": "write",
          "argsType": "{ content: string; asHtml?: boolean }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "content": {
                "type": "string",
                "description": "Content to insert at the caret."
              },
              "asHtml": {
                "type": "boolean",
                "description": "Treat content as HTML (sanitised). Pass false for plain text. Defaults to true."
              }
            },
            "required": [
              "content"
            ]
          },
          "examples": [
            {
              "args": {
                "content": "{{patient.firstName}}",
                "asHtml": false
              },
              "note": "Insert a merge variable as plain text."
            }
          ],
          "description": "Insert content at the caret (replacing any selection). HTML is sanitised; pass asHtml:false for plain text. Seam for merge/template variables and AI-generated drafts.",
          "descriptionKey": "ui.agent.richTextEditor.actions.insertAtCursor"
        },
        {
          "name": "apply_format",
          "safety": "write",
          "argsType": "{ format: 'bold' | 'italic' | 'strikethrough' | 'bulletedList' | 'numberedList' | 'heading' | 'quote' | 'paragraph' }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "format": {
                "type": "string",
                "enum": [
                  "bold",
                  "italic",
                  "strikethrough",
                  "bulletedList",
                  "numberedList",
                  "heading",
                  "quote",
                  "paragraph"
                ],
                "description": "Block or inline format to toggle/apply."
              }
            },
            "required": [
              "format"
            ]
          },
          "examples": [
            {
              "args": {
                "format": "bold"
              },
              "note": "Bold the selection."
            }
          ],
          "description": "Toggle/apply a block or inline format on the current selection (bold, italic, strikethrough, bulleted/numbered list, heading, quote, paragraph).",
          "descriptionKey": "ui.agent.richTextEditor.actions.applyFormat"
        },
        {
          "name": "clear",
          "safety": "destructive",
          "idempotent": true,
          "description": "Empty the editor. Loses unsaved input.",
          "descriptionKey": "ui.agent.richTextEditor.actions.clear"
        },
        {
          "name": "focus",
          "safety": "read",
          "idempotent": true,
          "description": "Move keyboard focus to the editor surface.",
          "descriptionKey": "ui.agent.richTextEditor.actions.focus"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "rich-text-editor"
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "scroll-area",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "scroll-area",
          "description": "Marks the element as a kit ScrollArea."
        }
      }
    },
    {
      "kind": "component",
      "id": "search-bar",
      "capabilities": [
        "filter",
        "submit"
      ],
      "state": [
        {
          "name": "query",
          "type": "string",
          "description": "Current raw query string (inline mode). Empty in launcher mode.",
          "descriptionKey": "ui.agent.searchBar.state.query"
        },
        {
          "name": "isEmpty",
          "type": "boolean",
          "description": "True when the query is empty.",
          "descriptionKey": "ui.agent.searchBar.state.isEmpty"
        }
      ],
      "actions": [
        {
          "name": "set_query",
          "safety": "read",
          "argsType": "{ query: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "query": {
                "type": "string",
                "description": "Filter text for the search."
              }
            },
            "required": [
              "query"
            ]
          },
          "idempotent": true,
          "description": "Replace the current query (inline mode only). No-op in launcher mode.",
          "descriptionKey": "ui.agent.searchBar.actions.setQuery"
        },
        {
          "name": "clear",
          "safety": "read",
          "idempotent": true,
          "description": "Clear the query and close the result popover.",
          "descriptionKey": "ui.agent.searchBar.actions.clear"
        },
        {
          "name": "submit",
          "safety": "read",
          "description": "In launcher mode opens the CommandPalette; in inline mode commits the highlighted option.",
          "descriptionKey": "ui.agent.searchBar.actions.submit"
        },
        {
          "name": "focus",
          "safety": "read",
          "idempotent": true,
          "description": "Move keyboard focus to the SearchBar.",
          "descriptionKey": "ui.agent.searchBar.actions.focus"
        },
        {
          "name": "apply_saved_search",
          "safety": "read",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "Saved-search id resolved by the host handler."
              }
            },
            "required": [
              "id"
            ]
          },
          "idempotent": true,
          "description": "Apply a saved-search by id. The host wires the actual query lookup; the adapter routes the id to its onApplySavedSearch handler. No-op when no handler is wired.",
          "descriptionKey": "ui.agent.searchBar.actions.applySavedSearch"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "search-bar",
          "description": "Marks the SearchBar root."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "search-input",
      "capabilities": [
        "filter"
      ],
      "state": [
        {
          "name": "query",
          "type": "string",
          "description": "Current raw query string (not debounced).",
          "descriptionKey": "ui.agent.searchInput.state.query"
        },
        {
          "name": "isEmpty",
          "type": "boolean",
          "description": "True when the query is empty.",
          "descriptionKey": "ui.agent.searchInput.state.isEmpty"
        }
      ],
      "actions": [
        {
          "name": "set_query",
          "safety": "read",
          "argsType": "{ query: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "query": {
                "type": "string",
                "description": "Filter text for the input."
              }
            },
            "required": [
              "query"
            ]
          },
          "idempotent": true,
          "description": "Replace the current query with the given string and fire onChange immediately.",
          "descriptionKey": "ui.agent.searchInput.actions.setQuery"
        },
        {
          "name": "clear",
          "safety": "read",
          "idempotent": true,
          "description": "Clear the query and return focus to the input.",
          "descriptionKey": "ui.agent.searchInput.actions.clear"
        },
        {
          "name": "submit",
          "safety": "read",
          "description": "Fire the current query without waiting for debounce.",
          "descriptionKey": "ui.agent.searchInput.actions.submit"
        },
        {
          "name": "focus",
          "safety": "read",
          "idempotent": true,
          "description": "Move keyboard focus to the input (expanding it first if `variant=\"expandable\"`).",
          "descriptionKey": "ui.agent.searchInput.actions.focus"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "search-input",
          "description": "Marks the SearchInput wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "section-card",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "section-card",
          "description": "Marks the element as a kit SectionCard."
        }
      }
    },
    {
      "kind": "component",
      "id": "select",
      "capabilities": [
        "select_single",
        "set_value",
        "open",
        "close"
      ],
      "state": [
        {
          "name": "value",
          "type": "string",
          "description": "Currently selected option value, or empty string when none.",
          "descriptionKey": "ui.agent.select.state.value"
        },
        {
          "name": "isOpen",
          "type": "boolean",
          "description": "Whether the option list is open.",
          "descriptionKey": "ui.agent.select.state.isOpen"
        }
      ],
      "actions": [
        {
          "name": "set_value",
          "safety": "write",
          "argsType": "{ value: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "value": {
                "type": "string",
                "description": "Option value to select."
              }
            },
            "required": [
              "value"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "value": "it"
              },
              "note": "Select the \"it\" option."
            }
          ],
          "description": "Select the option with the given value. A value that is not among the options, belongs to a disabled option, or is an action option (such as New signatory), is ignored and the selection stays as it was.",
          "descriptionKey": "ui.agent.select.actions.setValue"
        },
        {
          "name": "clear",
          "safety": "destructive",
          "idempotent": true,
          "description": "Clear the current selection.",
          "descriptionKey": "ui.agent.select.actions.clear"
        },
        {
          "name": "open",
          "safety": "read",
          "idempotent": true,
          "description": "Open the option list.",
          "descriptionKey": "ui.agent.select.actions.open"
        },
        {
          "name": "close",
          "safety": "read",
          "idempotent": true,
          "description": "Close the option list.",
          "descriptionKey": "ui.agent.select.actions.close"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "select",
          "description": "Marks the Select trigger."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        },
        "item": {
          "attr": "data-option-id",
          "description": "Stable opaque option value emitted on each rendered option."
        }
      }
    },
    {
      "kind": "component",
      "id": "separator",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "separator",
          "description": "Marks the element as a kit Separator."
        }
      }
    },
    {
      "kind": "component",
      "id": "session-countdown",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "session-countdown",
          "description": "Marks the element as a kit SessionCountdown banner. The root also emits `data-tone=\"running\" | \"warning\" | \"expired\"` (derived from the remaining time). The accessible remaining-time announcement is surfaced via the region's aria-label and a nested polite live region."
        }
      }
    },
    {
      "kind": "component",
      "id": "sheet",
      "capabilities": [
        "open",
        "close",
        "dismiss"
      ],
      "state": [
        {
          "name": "isOpen",
          "type": "boolean",
          "description": "True when the sheet is currently open.",
          "descriptionKey": "ui.agent.sheet.state.isOpen"
        }
      ],
      "actions": [
        {
          "name": "open",
          "safety": "read",
          "idempotent": true,
          "description": "Open the sheet.",
          "descriptionKey": "ui.agent.sheet.actions.open"
        },
        {
          "name": "close",
          "safety": "read",
          "idempotent": true,
          "description": "Close the sheet. Reversible by reopening.",
          "descriptionKey": "ui.agent.sheet.actions.close"
        },
        {
          "name": "dismiss",
          "safety": "destructive",
          "idempotent": true,
          "description": "Dismiss the sheet. Loses any in-progress input that has not been committed.",
          "descriptionKey": "ui.agent.sheet.actions.dismiss"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "sheet"
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop on Sheet.Root."
        }
      }
    },
    {
      "kind": "component",
      "id": "sidebar",
      "capabilities": [
        "expand"
      ],
      "state": [
        {
          "name": "isCollapsed",
          "type": "boolean",
          "description": "True when the sidebar is in its collapsed (rail) state.",
          "descriptionKey": "ui.agent.sidebar.state.isCollapsed"
        },
        {
          "name": "anySectionOpen",
          "type": "boolean",
          "description": "True while any foldable section is open.",
          "descriptionKey": "ui.agent.sidebar.state.anySectionOpen"
        }
      ],
      "actions": [
        {
          "name": "toggle_collapsed",
          "safety": "read",
          "description": "Toggle the sidebar between collapsed and expanded.",
          "descriptionKey": "ui.agent.sidebar.actions.toggleCollapsed"
        },
        {
          "name": "set_all_sections_open",
          "safety": "read",
          "argsType": "{ open: boolean }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "open": {
                "type": "boolean"
              }
            },
            "required": [
              "open"
            ]
          },
          "idempotent": true,
          "description": "Fold (false) or unfold (true) every foldable section, as the sections toggle does.",
          "descriptionKey": "ui.agent.sidebar.actions.setAllSectionsOpen"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "sidebar"
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        },
        "item": {
          "attr": "data-nav-id",
          "sourceProp": "navId",
          "description": "Each Sidebar.Item emits its `navId` prop as data-nav-id. Agents activate a nav item via native click on the matching anchor."
        }
      }
    },
    {
      "kind": "component",
      "id": "sign-document",
      "capabilities": [
        "submit"
      ],
      "state": [
        {
          "name": "isReadComplete",
          "type": "boolean",
          "description": "True when the reader has reached the last page (or read-gating is off).",
          "descriptionKey": "signDocument.agent.state.isReadComplete"
        }
      ],
      "actions": [
        {
          "name": "submit",
          "safety": "write",
          "returns": "SignatureConfirmPayload | null",
          "returnsSchema": {
            "oneOf": [
              {
                "type": "object",
                "description": "The confirmed signature payload (PNG data URL + metadata).",
                "properties": {
                  "dataUrl": {
                    "type": "string",
                    "description": "PNG data URL of the rendered signature."
                  }
                },
                "required": [
                  "dataUrl"
                ]
              },
              {
                "type": "null",
                "description": "Returned when there is no signature to confirm."
              }
            ]
          },
          "description": "Confirm the current signature and emit it via onSign. No-op if unsigned.",
          "descriptionKey": "signDocument.agent.actions.confirm"
        },
        {
          "name": "reset",
          "safety": "destructive",
          "idempotent": true,
          "description": "Clear the captured signature and return to the unsigned state.",
          "descriptionKey": "signDocument.agent.actions.reset"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "sign-document",
          "description": "Marks the SignDocument wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "sign-in-with-alfadocs-button",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "sign-in-with-alfadocs-button",
          "description": "Marks the branded sign-in trigger. Safety is declared by the host auth pattern."
        }
      }
    },
    {
      "kind": "component",
      "id": "signature-capture",
      "capabilities": [
        "capture",
        "submit"
      ],
      "state": [
        {
          "name": "isEmpty",
          "type": "boolean",
          "description": "True when no signature has been drawn or typed.",
          "descriptionKey": "ui.agent.signatureCapture.state.isEmpty"
        }
      ],
      "actions": [
        {
          "name": "clear",
          "safety": "destructive",
          "idempotent": true,
          "description": "Erase the current signature. Loses unsaved input.",
          "descriptionKey": "ui.agent.signatureCapture.actions.clear"
        },
        {
          "name": "undo",
          "safety": "write",
          "description": "Undo the last stroke.",
          "descriptionKey": "ui.agent.signatureCapture.actions.undo"
        },
        {
          "name": "confirm",
          "safety": "write",
          "returns": "SignatureConfirmPayload | null",
          "returnsSchema": {
            "oneOf": [
              {
                "type": "object",
                "description": "The committed signature payload.",
                "properties": {
                  "dataUrl": {
                    "type": "string",
                    "description": "PNG data URL of the captured signature."
                  },
                  "capturedAt": {
                    "type": "string",
                    "description": "ISO-8601 UTC timestamp of the commit."
                  }
                },
                "required": [
                  "dataUrl"
                ]
              },
              {
                "type": "null",
                "description": "Returned when the pad is empty."
              }
            ]
          },
          "description": "Commit the signature and return its serialised payload.",
          "descriptionKey": "ui.agent.signatureCapture.actions.confirm"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "signature-capture"
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "signature-field",
      "capabilities": [
        "capture"
      ],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "signature-field",
          "description": "Marks the SignatureField button. Emits `data-state` (unsigned / signing / signed) reflecting the controlled lifecycle, and `data-active` when the field is the current field-to-field navigation target."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop. Required to address one signature field among the N placed over a PDF page."
        }
      }
    },
    {
      "kind": "component",
      "id": "signature-status-chip",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "signature-status-chip",
          "description": "Marks the element as a kit SignatureStatusChip. The root also emits data-status (signed | partial | unsigned | notRequired) — the derived state only, never the document."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop — the consumer-supplied document identifier."
        }
      }
    },
    {
      "kind": "component",
      "id": "skeleton",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "skeleton",
          "description": "Marks the element as a kit Skeleton placeholder. A preset root also carries data-preset: figure, line-chart, bar-chart, heatmap, table or list. Decorative; the busy region around it says what is loading."
        }
      }
    },
    {
      "kind": "component",
      "id": "skeleton-scheme",
      "capabilities": [
        "pick",
        "set_value",
        "edit_inline",
        "view_change"
      ],
      "state": [
        {
          "name": "chart",
          "type": "object",
          "description": "Current skeletal chart — findings keyed by bone region id. Notes are PHI and omitted from this snapshot; read them per-region via get_region.",
          "descriptionKey": "ui.agent.skeletonScheme.state.chart"
        },
        {
          "name": "activeView",
          "type": "string",
          "description": "Id of the currently displayed skeletal view.",
          "descriptionKey": "ui.agent.skeletonScheme.state.activeView"
        }
      ],
      "actions": [
        {
          "name": "focus_region",
          "safety": "read",
          "argsType": "{ regionId: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "regionId": {
                "type": "string",
                "description": "Per-bone region id within the active view, e.g. 'femur-r', 'tibia-l', 'humerus-r', 'ribs-l', 'lumbar-spine', 'skull'. Bilateral bones carry a '-r' / '-l' anatomical-side suffix; midline bones (spine, skull, sternum, sacrum) have none."
              }
            },
            "required": [
              "regionId"
            ]
          },
          "idempotent": true,
          "description": "Move focus to a specific bone in the active view.",
          "descriptionKey": "ui.agent.skeletonScheme.actions.focusRegion"
        },
        {
          "name": "get_region",
          "safety": "phi",
          "argsType": "{ regionId: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "regionId": {
                "type": "string",
                "description": "Per-bone region id within the active view, e.g. 'femur-r', 'tibia-l', 'humerus-r', 'ribs-l', 'lumbar-spine', 'skull'. Bilateral bones carry a '-r' / '-l' anatomical-side suffix; midline bones (spine, skull, sternum, sacrum) have none."
              }
            },
            "required": [
              "regionId"
            ]
          },
          "returns": "SkeletonFinding[]",
          "returnsSchema": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "type": {
                  "enum": [
                    "observation",
                    "lesion",
                    "pain",
                    "treatment",
                    "note"
                  ]
                },
                "note": {
                  "type": "string"
                }
              },
              "required": [
                "type"
              ]
            }
          },
          "idempotent": true,
          "description": "Read the findings (incl. notes) recorded on one bone.",
          "descriptionKey": "ui.agent.skeletonScheme.actions.getRegion"
        },
        {
          "name": "regions_with",
          "safety": "read",
          "argsType": "{ type: FindingType }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "type": {
                "enum": [
                  "observation",
                  "lesion",
                  "pain",
                  "treatment",
                  "note"
                ]
              }
            },
            "required": [
              "type"
            ]
          },
          "returns": "string[]",
          "returnsSchema": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "Per-bone region id within the active view, e.g. 'femur-r', 'tibia-l', 'humerus-r', 'ribs-l', 'lumbar-spine', 'skull'. Bilateral bones carry a '-r' / '-l' anatomical-side suffix; midline bones (spine, skull, sternum, sacrum) have none."
            }
          },
          "idempotent": true,
          "description": "List the bone region ids carrying a given finding type.",
          "descriptionKey": "ui.agent.skeletonScheme.actions.regionsWith"
        },
        {
          "name": "set_finding",
          "safety": "write",
          "argsType": "{ regionId: string; type: FindingType; note?: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "regionId": {
                "type": "string",
                "description": "Per-bone region id within the active view, e.g. 'femur-r', 'tibia-l', 'humerus-r', 'ribs-l', 'lumbar-spine', 'skull'. Bilateral bones carry a '-r' / '-l' anatomical-side suffix; midline bones (spine, skull, sternum, sacrum) have none."
              },
              "type": {
                "enum": [
                  "observation",
                  "lesion",
                  "pain",
                  "treatment",
                  "note"
                ]
              },
              "note": {
                "type": "string"
              }
            },
            "required": [
              "regionId",
              "type"
            ]
          },
          "idempotent": true,
          "description": "Record a finding (observation / lesion / pain / treatment / note) on a bone.",
          "descriptionKey": "ui.agent.skeletonScheme.actions.setFinding"
        },
        {
          "name": "remove_finding",
          "safety": "write",
          "argsType": "{ regionId: string; type: FindingType }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "regionId": {
                "type": "string",
                "description": "Per-bone region id within the active view, e.g. 'femur-r', 'tibia-l', 'humerus-r', 'ribs-l', 'lumbar-spine', 'skull'. Bilateral bones carry a '-r' / '-l' anatomical-side suffix; midline bones (spine, skull, sternum, sacrum) have none."
              },
              "type": {
                "enum": [
                  "observation",
                  "lesion",
                  "pain",
                  "treatment",
                  "note"
                ]
              }
            },
            "required": [
              "regionId",
              "type"
            ]
          },
          "idempotent": true,
          "description": "Remove a single finding type from a bone.",
          "descriptionKey": "ui.agent.skeletonScheme.actions.removeFinding"
        },
        {
          "name": "clear_region",
          "safety": "destructive",
          "argsType": "{ regionId: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "regionId": {
                "type": "string",
                "description": "Per-bone region id within the active view, e.g. 'femur-r', 'tibia-l', 'humerus-r', 'ribs-l', 'lumbar-spine', 'skull'. Bilateral bones carry a '-r' / '-l' anatomical-side suffix; midline bones (spine, skull, sternum, sacrum) have none."
              }
            },
            "required": [
              "regionId"
            ]
          },
          "idempotent": true,
          "description": "Clear every finding from a bone.",
          "descriptionKey": "ui.agent.skeletonScheme.actions.clearRegion"
        },
        {
          "name": "set_view",
          "safety": "write",
          "argsType": "{ viewId: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "viewId": {
                "type": "string",
                "description": "View id, one of 'skeletal-front' / 'skeletal-back'."
              }
            },
            "required": [
              "viewId"
            ]
          },
          "idempotent": true,
          "description": "Switch the active skeletal view.",
          "descriptionKey": "ui.agent.skeletonScheme.actions.setView"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "skeleton-scheme"
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        },
        "item": {
          "attr": "data-region",
          "description": "Each rendered bone `<g>` carries its region id as `data-region` and its anatomical side (`left` / `right` / `midline`) as `data-side`, so bilateral bones can be disambiguated by side. The root `data-view` attribute exposes the active skeletal view."
        }
      }
    },
    {
      "kind": "component",
      "id": "skip-link",
      "capabilities": [
        "navigate"
      ],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "skip-link",
          "description": "Marks the SkipLink anchor. Destination is the native `href` attribute."
        }
      }
    },
    {
      "kind": "component",
      "id": "slider",
      "capabilities": [
        "set_value",
        "range_pick"
      ],
      "state": [
        {
          "name": "value",
          "type": "number[]",
          "description": "Current thumb values; length 1 for a single slider, length 2 for a range.",
          "descriptionKey": "ui.agent.slider.state.value"
        }
      ],
      "actions": [
        {
          "name": "set_value",
          "safety": "write",
          "argsType": "{ value: number[] }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "value": {
                "type": "array",
                "items": {
                  "type": "number"
                },
                "minItems": 1,
                "maxItems": 2,
                "description": "Thumb value(s): a 1-tuple for a single slider, a 2-tuple for a range."
              }
            },
            "required": [
              "value"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "value": [
                  50
                ]
              },
              "note": "Set a single slider to 50."
            },
            {
              "args": {
                "value": [
                  20,
                  80
                ]
              },
              "note": "Set a range to 20–80."
            }
          ],
          "description": "Replace the thumb value(s). Pass a 1-tuple for single, 2-tuple for range.",
          "descriptionKey": "ui.agent.slider.actions.setValue"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "slider",
          "description": "Marks the Slider root."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "slot-grid",
      "capabilities": [
        "pick",
        "range_navigate",
        "expand"
      ],
      "state": [
        {
          "name": "status",
          "type": "'default' | 'loading' | 'disabled' | 'empty'",
          "description": "Visual state of the grid. Read this before concluding \"no availability\" — `loading` means the window has not resolved yet.",
          "descriptionKey": "ui.agent.slotGrid.state.status"
        },
        {
          "name": "selectedSlotId",
          "type": "string | null",
          "description": "Id of the slot the consumer has committed as selected, or null. Reflects the controlled `selectedSlotId` prop, not an internal choice.",
          "descriptionKey": "ui.agent.slotGrid.state.selectedSlotId"
        },
        {
          "name": "visibleDays",
          "type": "string[]",
          "description": "Calendar days currently rendered as columns, as `yyyy-MM-dd` keys in display order.",
          "descriptionKey": "ui.agent.slotGrid.state.visibleDays"
        },
        {
          "name": "slotsByDay",
          "type": "Record<string, string[]>",
          "description": "Map of day key (`yyyy-MM-dd`) to the ids of that day’s bookable slots. Ids only — never slot or patient objects. Includes slots still collapsed behind \"Show more\".",
          "descriptionKey": "ui.agent.slotGrid.state.slotsByDay"
        },
        {
          "name": "expandedDays",
          "type": "string[]",
          "description": "Day keys whose \"Show more\" control has been used, so every slot for that day is rendered.",
          "descriptionKey": "ui.agent.slotGrid.state.expandedDays"
        },
        {
          "name": "hasPrevious",
          "type": "boolean",
          "description": "True when an earlier window of days exists — the \"previous days\" arrow is offered.",
          "descriptionKey": "ui.agent.slotGrid.state.hasPrevious"
        },
        {
          "name": "hasNext",
          "type": "boolean",
          "description": "True when a later window of days exists — the \"next days\" arrow is offered.",
          "descriptionKey": "ui.agent.slotGrid.state.hasNext"
        }
      ],
      "actions": [
        {
          "name": "select_slot",
          "safety": "write",
          "argsType": "{ slotId: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "slotId": {
                "type": "string",
                "description": "Id of the slot to select. Must be one of the ids returned by the `slotsByDay` state slot."
              }
            },
            "required": [
              "slotId"
            ]
          },
          "returns": "boolean",
          "returnsSchema": {
            "type": "boolean",
            "description": "True when the selection callback fired."
          },
          "idempotent": true,
          "errors": [
            "Returns false when no slot with that id is in the visible window — page with next_days / previous_days first.",
            "Returns false when the slot is unavailable, or the grid is loading or disabled."
          ],
          "examples": [
            {
              "args": {
                "slotId": "avail-2026-09-01-0930"
              },
              "note": "Book the 09:30 slot on 1 September."
            }
          ],
          "description": "Select an available slot by id. Emits the same selection the user would by clicking the slot button.",
          "descriptionKey": "ui.agent.slotGrid.actions.selectSlot"
        },
        {
          "name": "next_days",
          "safety": "read",
          "returns": "boolean",
          "returnsSchema": {
            "type": "boolean",
            "description": "True when the paging callback fired."
          },
          "errors": [
            "Returns false when `hasNext` is false, or the grid is loading or disabled."
          ],
          "description": "Page the visible window forward to the next group of days, as the \"next days\" arrow does.",
          "descriptionKey": "ui.agent.slotGrid.actions.nextDays"
        },
        {
          "name": "previous_days",
          "safety": "read",
          "returns": "boolean",
          "returnsSchema": {
            "type": "boolean",
            "description": "True when the paging callback fired."
          },
          "errors": [
            "Returns false when `hasPrevious` is false, or the grid is loading or disabled."
          ],
          "description": "Page the visible window back to the previous group of days, as the \"previous days\" arrow does.",
          "descriptionKey": "ui.agent.slotGrid.actions.previousDays"
        },
        {
          "name": "show_more_day",
          "safety": "read",
          "argsType": "{ dayKey: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "dayKey": {
                "type": "string",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                "description": "Day to expand, as a `yyyy-MM-dd` key from the `visibleDays` state slot."
              }
            },
            "required": [
              "dayKey"
            ]
          },
          "returns": "boolean",
          "returnsSchema": {
            "type": "boolean",
            "description": "True when the day was expanded."
          },
          "idempotent": true,
          "errors": [
            "Returns false when the day key is not one of the visible columns, or the grid is loading or disabled."
          ],
          "examples": [
            {
              "args": {
                "dayKey": "2026-09-01"
              },
              "note": "Reveal the rest of 1 September so every slot button is clickable."
            }
          ],
          "description": "Render every slot for one day, as the day’s \"Show more\" button does. Only affects what is on screen — `slotsByDay` already lists collapsed slots.",
          "descriptionKey": "ui.agent.slotGrid.actions.showMoreDay"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "slot-grid",
          "description": "Marks the SlotGrid region. Emits `data-state` reflecting the public `state` prop (default / loading / disabled / empty)."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the `id` prop. Also the registry key — without an `id` the instance does not register, so the handle-driven actions are unreachable and only the DOM channel works."
        },
        "item": {
          "attr": "data-slot-id",
          "sourceProp": "days[].slots[].id",
          "description": "Per-slot button identifier sourced from each `SlotGridSlot.id` — an availability id, never a patient id. DOM-driving agents activate a slot via native click on the matching button."
        }
      }
    },
    {
      "kind": "component",
      "id": "smart-date",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "smart-date",
          "description": "Marks the element as a kit SmartDate. The root also emits `data-state` carrying the bucketed temporal state — one of `overdue` | `past` | `today` | `tomorrow` | `soon` | `upcoming` (the `SmartDateState` union) — so an agent can read how the date relates to \"now\" without re-deriving it. The machine-readable date lives in the native `datetime` attribute on the `<time>` root."
        }
      }
    },
    {
      "kind": "component",
      "id": "social-sign-in-button",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "social-sign-in-button",
          "description": "Marks the branded provider sign-in trigger (Apple / Google). The active provider is on `data-provider`. Safety is declared by the host auth pattern."
        }
      }
    },
    {
      "kind": "component",
      "id": "sparkline",
      "capabilities": [],
      "state": [
        {
          "name": "annotationIds",
          "type": "string[]",
          "description": "Ids of the annotations currently drawn, in declaration order. The only ids `select_annotation` will accept — check against this before calling. Ids only, never annotation labels.",
          "descriptionKey": "ui.agent.sparkline.state.annotationIds"
        },
        {
          "name": "selectable",
          "type": "boolean",
          "description": "True when the host wired an annotation-select handler. False means every `select_annotation` call is a no-op, whatever id is passed.",
          "descriptionKey": "ui.agent.sparkline.state.selectable"
        },
        {
          "name": "pointCount",
          "type": "number",
          "description": "Number of positions in the currently rendered series, unmeasured gaps included — reflecting whichever applied last, the `data` prop or an `update_series` call. A count only; the plotted values are never exposed.",
          "descriptionKey": "ui.agent.sparkline.state.pointCount"
        }
      ],
      "actions": [
        {
          "name": "update_series",
          "safety": "write",
          "argsType": "{ data: number[] }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "type": "number"
                },
                "description": "The new data points to render."
              }
            },
            "required": [
              "data"
            ]
          },
          "idempotent": true,
          "errors": [
            "Per-point tooltip titles are hidden after this call — the host point labels describe the previous series, not the one written."
          ],
          "description": "Replace the sparkline data without remounting. Writes straight into ApexCharts, bypassing React — read the `pointCount` slot back rather than expecting the host tree to reflect it. Host-supplied point labels are not updated, so the tooltip title is hidden after this call.",
          "descriptionKey": "ui.agent.sparkline.actions.updateSeries"
        },
        {
          "name": "export_png",
          "safety": "read",
          "returns": "string",
          "returnsSchema": {
            "type": "string",
            "description": "A PNG image of the sparkline encoded as a data URI."
          },
          "description": "Return a PNG data URI of the sparkline.",
          "descriptionKey": "ui.agent.sparkline.actions.exportPng"
        },
        {
          "name": "select_annotation",
          "safety": "write",
          "argsType": "{ annotationId: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "annotationId": {
                "type": "string",
                "description": "The annotation's id, as carried by data-annotation-hit-id on the pressable band. The decorative drawn marker carries the same value as data-annotation-id, but is not selectable."
              }
            },
            "required": [
              "annotationId"
            ]
          },
          "idempotent": true,
          "errors": [
            "Silently ignored when `selectable` is false — the host wired no annotation-select handler.",
            "Silently ignored when the id is not in `annotationIds` — that annotation is not currently drawn."
          ],
          "description": "Select a drawn annotation, as pressing its band would. No-op unless the host wired onAnnotationSelect and the id names an annotation that is currently drawn — check the `selectable` and `annotationIds` slots first, since neither failure produces a signal.",
          "descriptionKey": "ui.agent.sparkline.actions.selectAnnotation"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "sparkline"
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "spinner",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "spinner",
          "description": "Marks the element as a kit Spinner."
        }
      }
    },
    {
      "kind": "component",
      "id": "stat",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "stat",
          "description": "Marks the element as a kit Stat tile."
        }
      }
    },
    {
      "kind": "component",
      "id": "stepper-accordion",
      "capabilities": [
        "expand",
        "navigate"
      ],
      "state": [
        {
          "name": "currentStep",
          "type": "number",
          "description": "Zero-indexed active step.",
          "descriptionKey": "ui.agent.stepperAccordion.state.currentStep"
        },
        {
          "name": "totalSteps",
          "type": "number",
          "description": "Total number of steps in the flow.",
          "descriptionKey": "ui.agent.stepperAccordion.state.totalSteps"
        },
        {
          "name": "openSteps",
          "type": "number[]",
          "description": "Indices of currently-open step panels (singleton under Radix single mode).",
          "descriptionKey": "ui.agent.stepperAccordion.state.openSteps"
        }
      ],
      "actions": [
        {
          "name": "goto_step",
          "safety": "read",
          "argsType": "{ step: number }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "step": {
                "type": "integer",
                "minimum": 0
              }
            },
            "required": [
              "step"
            ]
          },
          "idempotent": true,
          "description": "Activate the given step. Upcoming steps are gated by the consumer’s validation in onStepChange.",
          "descriptionKey": "ui.agent.stepperAccordion.actions.gotoStep"
        },
        {
          "name": "next",
          "safety": "read",
          "description": "Advance to the next step. Subject to the consumer’s onStepChange validation.",
          "descriptionKey": "ui.agent.stepperAccordion.actions.next"
        },
        {
          "name": "previous",
          "safety": "read",
          "description": "Return to the previous step (re-opens a completed step in edit mode).",
          "descriptionKey": "ui.agent.stepperAccordion.actions.previous"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "stepper-accordion",
          "description": "Marks the StepperAccordion root."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        },
        "item": {
          "attr": "data-step-id",
          "description": "Stable opaque id of a step (the zero-indexed step number as a string)."
        }
      }
    },
    {
      "kind": "component",
      "id": "stepper-progress",
      "capabilities": [
        "navigate"
      ],
      "state": [
        {
          "name": "currentStep",
          "type": "number",
          "description": "Zero-indexed active step.",
          "descriptionKey": "ui.agent.stepperProgress.state.currentStep"
        },
        {
          "name": "totalSteps",
          "type": "number",
          "description": "Total number of steps in the flow.",
          "descriptionKey": "ui.agent.stepperProgress.state.totalSteps"
        }
      ],
      "actions": [
        {
          "name": "goto_step",
          "safety": "read",
          "argsType": "{ step: number }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "step": {
                "type": "integer",
                "minimum": 0
              }
            },
            "required": [
              "step"
            ]
          },
          "idempotent": true,
          "description": "Request the host to activate the given step via onStepChange. No-op when no handler is wired.",
          "descriptionKey": "ui.agent.stepperProgress.actions.gotoStep"
        },
        {
          "name": "next",
          "safety": "read",
          "description": "Request the host to advance one step via onStepChange.",
          "descriptionKey": "ui.agent.stepperProgress.actions.next"
        },
        {
          "name": "previous",
          "safety": "read",
          "description": "Request the host to retreat one step via onStepChange.",
          "descriptionKey": "ui.agent.stepperProgress.actions.previous"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "stepper-progress",
          "description": "Marks the StepperProgress root."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "streaming-text",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "streaming-text",
          "description": "Marks the element as a kit StreamingText surface."
        }
      }
    },
    {
      "kind": "component",
      "id": "suggestion-chip",
      "capabilities": [
        "pick",
        "dismiss"
      ],
      "state": [
        {
          "name": "value",
          "type": "string",
          "description": "The chip's emitted value (its `value` prop or string child).",
          "descriptionKey": "ui.agent.suggestionChip.state.value"
        }
      ],
      "actions": [
        {
          "name": "select",
          "safety": "write",
          "description": "Activate the chip — fires onSelect and (by default) self-removes.",
          "descriptionKey": "ui.agent.suggestionChip.actions.select"
        },
        {
          "name": "dismiss",
          "safety": "destructive",
          "idempotent": true,
          "description": "Remove the chip without activating it.",
          "descriptionKey": "ui.agent.suggestionChip.actions.dismiss"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "suggestion-chip",
          "description": "Marks the chip button. Per chip — a parent rendering many chips ships its own item hook."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "switch",
      "capabilities": [
        "set_value"
      ],
      "state": [
        {
          "name": "checked",
          "type": "boolean",
          "description": "Whether the switch is on.",
          "descriptionKey": "ui.agent.switch.state.checked"
        }
      ],
      "actions": [
        {
          "name": "set_checked",
          "safety": "write",
          "argsType": "{ checked: boolean }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "checked": {
                "type": "boolean"
              }
            },
            "required": [
              "checked"
            ]
          },
          "idempotent": true,
          "description": "Set the on/off state to a specific value.",
          "descriptionKey": "ui.agent.switch.actions.setChecked"
        },
        {
          "name": "toggle",
          "safety": "write",
          "description": "Flip the on/off state.",
          "descriptionKey": "ui.agent.switch.actions.toggle"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "switch",
          "description": "Marks the Switch root."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "tab-bar",
      "capabilities": [
        "select_single",
        "navigate"
      ],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "tab-bar",
          "description": "Marks the TabBar navigation strip."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the optional `id` prop — scopes a `[data-tab-id]` lookup to one bar when several are on screen."
        },
        "item": {
          "attr": "data-tab-id",
          "sourceProp": "items[].id",
          "description": "Per-tab identifier sourced from each `TabBarItem.id` — a route / view key, never patient data. Emitted on the expanded strip’s `<a>` and `<button>` tabs and on the collapsed DropdownMenu item, so a DOM-driving agent activates a tab with a native click on the match. The active tab additionally carries `aria-current=\"page\"`."
        }
      }
    },
    {
      "kind": "component",
      "id": "tabs",
      "capabilities": [
        "select_single"
      ],
      "state": [
        {
          "name": "activeTab",
          "type": "string | null",
          "description": "Value of the currently-active tab.",
          "descriptionKey": "ui.agent.tabs.state.activeTab"
        }
      ],
      "actions": [
        {
          "name": "select_tab",
          "safety": "read",
          "argsType": "{ value: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "value": {
                "type": "string"
              }
            },
            "required": [
              "value"
            ]
          },
          "idempotent": true,
          "description": "Activate the tab with the given value.",
          "descriptionKey": "ui.agent.tabs.actions.selectTab"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "tabs"
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop on Tabs.Root."
        },
        "item": {
          "attr": "data-tab-id",
          "description": "Each Tab.Trigger emits its value as data-tab-id."
        }
      }
    },
    {
      "kind": "component",
      "id": "tag",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "tag",
          "description": "Marks the element as a kit Tag."
        }
      }
    },
    {
      "kind": "component",
      "id": "task-card",
      "capabilities": [
        "pick",
        "dismiss"
      ],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "task-card",
          "description": "Marks the element as a kit TaskCard. The card root also emits data-component-id sourced from item.id and data-status with the current lifecycle."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "item.id",
          "description": "Sourced from item.id — the stable task identifier."
        }
      }
    },
    {
      "kind": "component",
      "id": "task-editor",
      "capabilities": [
        "set_value",
        "submit",
        "dismiss"
      ],
      "state": [
        {
          "name": "status",
          "type": "'loading' | 'ready' | 'error' | 'locked' | 'withheld'",
          "description": "Where the form is: loading the task, ready, failed to load, locked (edit mode with nothing to load) or withheld behind the privacy notice. Writes need 'ready'.",
          "descriptionKey": "ui.agent.taskEditor.state.status"
        },
        {
          "name": "draft",
          "type": "{ mode: string; dateIso: string | null; about: string; patientId: string | null; companyId: string | null; operatorId: string | null; typeId: string | null; assigneeId: string | null; done: boolean; hasNote: boolean; noteLength: number }",
          "description": "The draft as Save would send it: ids and structure only, never the note body. done is the last value the host confirmed.",
          "descriptionKey": "ui.agent.taskEditor.state.draft"
        },
        {
          "name": "canSave",
          "type": "boolean",
          "description": "Whether save would reach the host now: the form is ready, the note is filled, a chosen counterpart has an id and no write is pending.",
          "descriptionKey": "ui.agent.taskEditor.state.canSave"
        }
      ],
      "actions": [
        {
          "name": "set_fields",
          "safety": "phi",
          "argsType": "{ dateIso?: string; note?: string; typeId?: string; assigneeId?: string | null; about?: 'nobody' | 'patient' | 'company' | 'operator'; patientId?: string; companyId?: string; operatorId?: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "dateIso": {
                "type": "string",
                "format": "date-time"
              },
              "note": {
                "type": "string"
              },
              "typeId": {
                "type": "string"
              },
              "assigneeId": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "about": {
                "type": "string",
                "enum": [
                  "nobody",
                  "patient",
                  "company",
                  "operator"
                ]
              },
              "patientId": {
                "type": "string"
              },
              "companyId": {
                "type": "string"
              },
              "operatorId": {
                "type": "string"
              }
            }
          },
          "idempotent": true,
          "errors": [
            "An id the host lists, its patient search or the stored task do not resolve.",
            "More than one of patientId, companyId and operatorId.",
            "The form is not ready, is read-only or is withheld."
          ],
          "description": "Set draft fields. Ids must come from the host lists, a patient the host search returned, or equal the stored one. At most one counterpart per call, and it selects its branch; assigneeId null is nobody. Nothing is saved.",
          "descriptionKey": "ui.agent.taskEditor.actions.setFields"
        },
        {
          "name": "save",
          "safety": "phi",
          "openWorld": true,
          "description": "Save the task through the host. Resolves once the write lands and rejects with the host error, which the form also shows.",
          "descriptionKey": "ui.agent.taskEditor.actions.save"
        },
        {
          "name": "set_done",
          "safety": "write",
          "argsType": "{ done: boolean }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "done": {
                "type": "boolean"
              }
            },
            "required": [
              "done"
            ]
          },
          "openWorld": true,
          "errors": [
            "The form is not ready, is read-only or has no Done seam.",
            "A save, a delete or another Done change is in flight.",
            "The task was already saved or deleted in this session."
          ],
          "description": "Mark an existing task done or not done through the host. A rejection rolls the switch back.",
          "descriptionKey": "ui.agent.taskEditor.actions.setDone"
        },
        {
          "name": "delete",
          "safety": "destructive",
          "idempotent": true,
          "openWorld": true,
          "description": "Delete the task through the host, without the confirmation dialog. Resolves once the delete lands.",
          "descriptionKey": "ui.agent.taskEditor.actions.delete"
        },
        {
          "name": "cancel",
          "safety": "destructive",
          "errors": [
            "A save or delete is in flight: wait for it to settle."
          ],
          "description": "Close the editor without saving. Anything typed since the last save is lost. Refused while a save or delete is in flight.",
          "descriptionKey": "ui.agent.taskEditor.actions.cancel"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "task-editor",
          "description": "Marks the TaskEditor body. It also carries data-variant and data-status. In the subview variant it sits inside the panel-subview section, which repeats data-component-id, data-variant and data-status and holds the heading and footer."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop, or generated. Addresses one editor from the agent. [data-component-id] reaches the footer actions in both variants."
        }
      }
    },
    {
      "kind": "component",
      "id": "task-tray",
      "capabilities": [
        "select_single",
        "dismiss"
      ],
      "state": [
        {
          "name": "items",
          "type": "Array<{ id: string; status: string }>",
          "description": "Currently-displayed tasks. Ids + status only — never task title / patient.",
          "descriptionKey": "ui.agent.taskTray.state.items"
        }
      ],
      "actions": [
        {
          "name": "select_item",
          "safety": "read",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              }
            },
            "required": [
              "id"
            ]
          },
          "idempotent": true,
          "description": "Activate the task with the given id.",
          "descriptionKey": "ui.agent.taskTray.actions.selectItem"
        },
        {
          "name": "toggle_done",
          "safety": "write",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              }
            },
            "required": [
              "id"
            ]
          },
          "description": "Request the host to toggle the done state of a task.",
          "descriptionKey": "ui.agent.taskTray.actions.toggleDone"
        },
        {
          "name": "dismiss",
          "safety": "destructive",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              }
            },
            "required": [
              "id"
            ]
          },
          "idempotent": true,
          "description": "Request the host to dismiss / remove the task with the given id.",
          "descriptionKey": "ui.agent.taskTray.actions.dismiss"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "task-tray",
          "description": "Marks the TaskTray wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop. Required to address a specific tray from the agent."
        },
        "item": {
          "attr": "data-task-id",
          "description": "Stable task id emitted on each rendered TaskCard inside the tray."
        }
      }
    },
    {
      "kind": "component",
      "id": "tasks-panel",
      "capabilities": [
        "pick",
        "dismiss",
        "scroll",
        "filter",
        "view_change",
        "paginate"
      ],
      "state": [
        {
          "name": "items",
          "type": "Array<{ id: string; status: string }>",
          "description": "Currently-rendered tasks. Ids + status only — never task note / patient.",
          "descriptionKey": "ui.agent.tasksPanel.state.items"
        }
      ],
      "actions": [
        {
          "name": "select_item",
          "safety": "read",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              }
            },
            "required": [
              "id"
            ]
          },
          "idempotent": true,
          "description": "Activate the task with the given id.",
          "descriptionKey": "ui.agent.tasksPanel.actions.selectItem"
        },
        {
          "name": "toggle_done",
          "safety": "write",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              }
            },
            "required": [
              "id"
            ]
          },
          "openWorld": true,
          "description": "Request the host to toggle the done state of a task.",
          "descriptionKey": "ui.agent.tasksPanel.actions.toggleDone"
        },
        {
          "name": "dismiss",
          "safety": "destructive",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              }
            },
            "required": [
              "id"
            ]
          },
          "idempotent": true,
          "openWorld": true,
          "description": "Request the host to dismiss / remove the task with the given id.",
          "descriptionKey": "ui.agent.tasksPanel.actions.dismiss"
        },
        {
          "name": "jump_to_overdue",
          "safety": "read",
          "idempotent": true,
          "description": "Re-anchor the panel scroll on the overdue tasks.",
          "descriptionKey": "ui.agent.tasksPanel.actions.jumpToOverdue"
        },
        {
          "name": "set_filter",
          "safety": "read",
          "argsType": "{ status?: 'todo' | 'done' | 'all'; type?: string | null; assignee?: string | null; overdueOnly?: boolean }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "status": {
                "type": "string",
                "enum": [
                  "todo",
                  "done",
                  "all"
                ]
              },
              "type": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "assignee": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "overdueOnly": {
                "type": "boolean"
              }
            }
          },
          "idempotent": true,
          "description": "Set the task filters (status segment, type, assignee, overdue-only). Omitted keys are left unchanged. Unchanged values are not re-sent. In server-filtered panels, choosing status 'done' clears overdueOnly.",
          "descriptionKey": "ui.agent.tasksPanel.actions.setFilter"
        },
        {
          "name": "change_scope",
          "safety": "read",
          "argsType": "{ scope: 'patient' | 'mine' }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "scope": {
                "type": "string",
                "enum": [
                  "patient",
                  "mine"
                ]
              }
            },
            "required": [
              "scope"
            ]
          },
          "idempotent": true,
          "description": "Switch the task scope segment between this patient ('patient') and the operator's own tasks ('mine'). The host re-feeds the items.",
          "descriptionKey": "ui.agent.tasksPanel.actions.changeScope"
        },
        {
          "name": "load_more",
          "safety": "read",
          "openWorld": true,
          "description": "Request the host to append the next page of tasks.",
          "descriptionKey": "ui.agent.tasksPanel.actions.loadMore"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "tasks-panel",
          "description": "Marks the TasksPanel wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop. Required to address a specific panel from the agent."
        },
        "item": {
          "attr": "data-task-id",
          "description": "Stable task id emitted on each rendered TaskCard inside the panel."
        }
      }
    },
    {
      "kind": "component",
      "id": "text-area",
      "capabilities": [
        "set_value",
        "edit_inline"
      ],
      "state": [
        {
          "name": "value",
          "type": "string",
          "description": "Current value of the textarea.",
          "descriptionKey": "ui.agent.textArea.state.value"
        },
        {
          "name": "isEmpty",
          "type": "boolean",
          "description": "Whether the textarea has no value.",
          "descriptionKey": "ui.agent.textArea.state.isEmpty"
        }
      ],
      "actions": [
        {
          "name": "set_value",
          "safety": "write",
          "argsType": "{ value: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "value": {
                "type": "string"
              }
            },
            "required": [
              "value"
            ]
          },
          "idempotent": true,
          "description": "Replace the textarea value.",
          "descriptionKey": "ui.agent.textArea.actions.setValue"
        },
        {
          "name": "clear",
          "safety": "destructive",
          "idempotent": true,
          "description": "Empty the textarea. Loses any typed value.",
          "descriptionKey": "ui.agent.textArea.actions.clear"
        },
        {
          "name": "focus",
          "safety": "read",
          "description": "Move keyboard focus to the textarea.",
          "descriptionKey": "ui.agent.textArea.actions.focus"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "text-area",
          "description": "Marks the TextArea wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "text-input",
      "capabilities": [
        "set_value"
      ],
      "state": [
        {
          "name": "value",
          "type": "string",
          "description": "Current value of the text input.",
          "descriptionKey": "ui.agent.textInput.state.value"
        },
        {
          "name": "isEmpty",
          "type": "boolean",
          "description": "Whether the input has no value.",
          "descriptionKey": "ui.agent.textInput.state.isEmpty"
        }
      ],
      "actions": [
        {
          "name": "set_value",
          "safety": "write",
          "argsType": "{ value: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "value": {
                "type": "string"
              }
            },
            "required": [
              "value"
            ]
          },
          "idempotent": true,
          "description": "Replace the input value.",
          "descriptionKey": "ui.agent.textInput.actions.setValue"
        },
        {
          "name": "clear",
          "safety": "destructive",
          "idempotent": true,
          "description": "Empty the input. Loses any typed value.",
          "descriptionKey": "ui.agent.textInput.actions.clear"
        },
        {
          "name": "focus",
          "safety": "read",
          "description": "Move keyboard focus to the input.",
          "descriptionKey": "ui.agent.textInput.actions.focus"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "text-input",
          "description": "Marks the TextInput wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "theme-root",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "theme-root",
          "description": "Marks the ThemeRoot wrapper. The active theme is encoded in the element's class list (`theme-light` / `theme-dark` / `theme-accessible`)."
        }
      }
    },
    {
      "kind": "component",
      "id": "theme-toggle",
      "capabilities": [
        "set_value"
      ],
      "state": [
        {
          "name": "currentTheme",
          "type": "ThemePreference",
          "description": "Active theme preference: light, dark, or system.",
          "descriptionKey": "ui.agent.themeToggle.state.currentTheme"
        },
        {
          "name": "currentAccessibility",
          "type": "AccessibilityPreference",
          "description": "Active accessibility preference: default or accessible.",
          "descriptionKey": "ui.agent.themeToggle.state.currentAccessibility"
        }
      ],
      "actions": [
        {
          "name": "set_theme",
          "safety": "write",
          "argsType": "{ theme: \"light\" | \"dark\" | \"system\" }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "theme": {
                "enum": [
                  "light",
                  "dark",
                  "system"
                ]
              }
            },
            "required": [
              "theme"
            ]
          },
          "idempotent": true,
          "description": "Switch the theme preference.",
          "descriptionKey": "ui.agent.themeToggle.actions.setTheme"
        },
        {
          "name": "set_accessibility",
          "safety": "write",
          "argsType": "{ accessibility: \"default\" | \"accessible\" }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "accessibility": {
                "enum": [
                  "default",
                  "accessible"
                ]
              }
            },
            "required": [
              "accessibility"
            ]
          },
          "idempotent": true,
          "description": "Switch the accessibility preference.",
          "descriptionKey": "ui.agent.themeToggle.actions.setAccessibility"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "theme-toggle",
          "description": "Marks the ThemeToggle wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "time-picker",
      "capabilities": [
        "select_single",
        "set_value",
        "open",
        "close"
      ],
      "state": [
        {
          "name": "value",
          "type": "HH:MM | null",
          "description": "Currently selected time as 24h HH:MM. Null when unset with allowEmpty; otherwise defaults to 00:00.",
          "descriptionKey": "ui.agent.timePicker.state.value"
        },
        {
          "name": "isOpen",
          "type": "boolean",
          "description": "Whether the time dropdown is open. Always false unless the picker has the dropdown prop.",
          "descriptionKey": "ui.agent.timePicker.state.isOpen"
        }
      ],
      "actions": [
        {
          "name": "set_time",
          "safety": "write",
          "argsType": "{ time: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "time": {
                "type": "string",
                "pattern": "^([01][0-9]|2[0-3]):[0-5][0-9]$"
              }
            },
            "required": [
              "time"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "time": "14:30"
              },
              "note": "2:30 PM in 24h form."
            }
          ],
          "description": "Set the time using a 24h HH:MM string.",
          "descriptionKey": "ui.agent.timePicker.actions.setTime"
        },
        {
          "name": "clear",
          "safety": "destructive",
          "idempotent": true,
          "description": "Clear to null with allowEmpty; otherwise reset to 00:00.",
          "descriptionKey": "ui.agent.timePicker.actions.clear"
        },
        {
          "name": "open",
          "safety": "read",
          "description": "Open the time dropdown without moving focus. A no-op unless the picker has the dropdown prop and is enabled.",
          "descriptionKey": "ui.agent.timePicker.actions.open"
        },
        {
          "name": "close",
          "safety": "read",
          "description": "Close the time dropdown. A no-op unless the picker has the dropdown prop.",
          "descriptionKey": "ui.agent.timePicker.actions.close"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "time-picker",
          "description": "Marks the TimePicker wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "timeline",
      "capabilities": [
        "select_single"
      ],
      "state": [
        {
          "name": "selectedEvent",
          "type": "string | null",
          "description": "Opaque event id of the currently-active event, or null.",
          "descriptionKey": "ui.agent.timeline.state.selectedEvent"
        }
      ],
      "actions": [
        {
          "name": "select_event",
          "safety": "read",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              }
            },
            "required": [
              "id"
            ]
          },
          "idempotent": true,
          "description": "Scroll the given event into view and mark it as selected.",
          "descriptionKey": "ui.agent.timeline.actions.selectEvent"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "timeline",
          "description": "Marks the Timeline root."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        },
        "item": {
          "attr": "data-event-id",
          "description": "Opaque event id emitted on each Timeline.Event when the `eventId` prop is provided."
        }
      }
    },
    {
      "kind": "component",
      "id": "timestamp",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "timestamp",
          "description": "Marks the element as a kit Timestamp. The machine-readable value lives in the native `datetime` attribute on the inner `<time>` element."
        }
      }
    },
    {
      "kind": "component",
      "id": "toast",
      "capabilities": [
        "dismiss"
      ],
      "state": [
        {
          "name": "visibleToasts",
          "type": "Array<{ id: string }>",
          "description": "Snapshot of currently-visible toasts by opaque id. Never carries the toast body text.",
          "descriptionKey": "ui.agent.toast.state.visibleToasts"
        }
      ],
      "actions": [
        {
          "name": "dismiss",
          "safety": "destructive",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              }
            },
            "required": [
              "id"
            ]
          },
          "idempotent": true,
          "description": "Dismiss the toast with the given id. Irreversible from the same UI.",
          "descriptionKey": "ui.agent.toast.actions.dismiss"
        },
        {
          "name": "dismiss_all",
          "safety": "destructive",
          "idempotent": true,
          "description": "Dismiss every visible toast.",
          "descriptionKey": "ui.agent.toast.actions.dismissAll"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "toast-region",
          "description": "Marks the Toaster region wrapper (data-component=\"toast-region\"). Toast is imperatively created; the registry addresses individual toasts by id, not by per-instance root."
        },
        "item": {
          "attr": "data-toast-id",
          "description": "Stable opaque toast id assigned at creation. Used by `dismiss({id})`."
        }
      }
    },
    {
      "kind": "component",
      "id": "token-insert-menu",
      "capabilities": [
        "open",
        "close"
      ],
      "state": [
        {
          "name": "isOpen",
          "type": "boolean",
          "description": "True when the token menu is currently open.",
          "descriptionKey": "ui.agent.tokenInsertMenu.state.isOpen"
        }
      ],
      "actions": [
        {
          "name": "open",
          "safety": "read",
          "idempotent": true,
          "description": "Open the token menu.",
          "descriptionKey": "ui.agent.tokenInsertMenu.actions.open"
        },
        {
          "name": "close",
          "safety": "read",
          "idempotent": true,
          "description": "Close the token menu.",
          "descriptionKey": "ui.agent.tokenInsertMenu.actions.close"
        },
        {
          "name": "insert",
          "safety": "write",
          "argsType": "{ token: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "token": {
                "type": "string"
              }
            },
            "required": [
              "token"
            ]
          },
          "examples": [
            {
              "args": {
                "token": "{{patient.name}}"
              },
              "note": "Emit the patient-name placeholder for cursor insertion."
            }
          ],
          "description": "Emit a merge-token to the consumer for cursor insertion.",
          "descriptionKey": "ui.agent.tokenInsertMenu.actions.insert"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "token-insert-menu",
          "description": "Marks the TokenInsertMenu wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "tool-rail",
      "capabilities": [
        "open",
        "close",
        "select_single"
      ],
      "state": [
        {
          "name": "activeToolId",
          "type": "string | null",
          "description": "Id of the tool whose panel is currently open, or null when the rail is collapsed to its strip. No panel content is ever exposed.",
          "descriptionKey": "ui.toolRail.agent.state.activeToolId"
        },
        {
          "name": "panelMode",
          "type": "'docked' | 'overlay' | 'full-screen'",
          "description": "How an open panel shows: docked beside the content, over it because the frame keeps a minimum width for main, or full screen on a phone.",
          "descriptionKey": "ui.agent.toolRail.state.panelMode"
        }
      ],
      "actions": [
        {
          "name": "open",
          "safety": "read",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              }
            },
            "required": [
              "id"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "id": "inbox"
              },
              "note": "Open the inbox tool panel."
            }
          ],
          "description": "Open the given tool's panel.",
          "descriptionKey": "ui.toolRail.agent.actions.open"
        },
        {
          "name": "close",
          "safety": "read",
          "idempotent": true,
          "description": "Collapse the rail to its strip (no active tool).",
          "descriptionKey": "ui.toolRail.agent.actions.close"
        },
        {
          "name": "select_tool",
          "safety": "read",
          "argsType": "{ id: string | null }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "id"
            ]
          },
          "idempotent": true,
          "description": "Set the active tool by id (opens its panel), or pass null to collapse.",
          "descriptionKey": "ui.toolRail.agent.actions.selectTool"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "tool-rail",
          "description": "Marks the ToolRail wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop. Required to address a specific rail from the agent."
        },
        "item": {
          "attr": "data-tool-id",
          "description": "Stable tool id emitted on each strip IconButton. The active icon also carries data-active set to its id."
        }
      }
    },
    {
      "kind": "component",
      "id": "tooltip",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "tooltip",
          "description": "Marks the element as a kit Tooltip content surface."
        }
      }
    },
    {
      "kind": "component",
      "id": "tooth-finding-palette",
      "capabilities": [
        "pick",
        "select_single",
        "set_value"
      ],
      "state": [
        {
          "name": "activeFinding",
          "type": "string | null",
          "description": "Id of the armed finding tool, or null when no tool is selected. Identifies a finding TYPE — never a patient, and never a charted finding.",
          "descriptionKey": "ui.agent.toothFindingPalette.state.activeFinding"
        },
        {
          "name": "status",
          "type": "string",
          "description": "Execution status the next charted finding takes — 'planned' or 'executed'.",
          "descriptionKey": "ui.agent.toothFindingPalette.state.status"
        },
        {
          "name": "tools",
          "type": "string[]",
          "description": "Every finding id the palette currently offers, in render order — built-ins plus any practice-defined ids. The authoritative vocabulary for select_finding.",
          "descriptionKey": "ui.agent.toothFindingPalette.state.tools"
        }
      ],
      "actions": [
        {
          "name": "select_finding",
          "safety": "read",
          "argsType": "{ condition: ConditionId }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "condition": {
                "type": "string",
                "description": "Finding id — either a built-in condition (the enum on tooth-scheme's set_finding: caries, filled, crowned, rootCanal, implant, …) or a practice-defined id supplied through the conditionRegistry prop. Read the live list from the `tools` state slot rather than guessing."
              }
            },
            "required": [
              "condition"
            ]
          },
          "idempotent": true,
          "errors": [
            "The condition is not among the palette's tools — read the \"tools\" state slot for the live list."
          ],
          "examples": [
            {
              "args": {
                "condition": "caries"
              },
              "note": "Arm the caries tool before marking a decayed surface."
            }
          ],
          "description": "Arm a finding tool, so the next tooth (or surface, or root) picked on the paired dental chart records that finding.",
          "descriptionKey": "ui.agent.toothFindingPalette.actions.selectFinding"
        },
        {
          "name": "clear_selection",
          "safety": "read",
          "idempotent": true,
          "description": "Disarm the palette so clicks on the chart stop recording a finding. Charted findings are untouched.",
          "descriptionKey": "ui.agent.toothFindingPalette.actions.clearSelection"
        },
        {
          "name": "set_status",
          "safety": "write",
          "argsType": "{ status: SymbolStatus }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "status": {
                "enum": [
                  "planned",
                  "executed"
                ],
                "description": "Execution status the next charted finding takes — 'planned' (proposed treatment) or 'executed' (work already carried out)."
              }
            },
            "required": [
              "status"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "status": "executed"
              },
              "note": "Record the next finding as work already carried out."
            }
          ],
          "description": "Choose whether the next charted finding is recorded as planned or executed.",
          "descriptionKey": "ui.agent.toothFindingPalette.actions.setStatus"
        },
        {
          "name": "focus_tool",
          "safety": "read",
          "argsType": "{ condition: ConditionId }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "condition": {
                "type": "string",
                "description": "Finding id — either a built-in condition (the enum on tooth-scheme's set_finding: caries, filled, crowned, rootCanal, implant, …) or a practice-defined id supplied through the conditionRegistry prop. Read the live list from the `tools` state slot rather than guessing."
              }
            },
            "required": [
              "condition"
            ]
          },
          "idempotent": true,
          "description": "Move keyboard focus to a tool without arming it — relocates the toolbar's single roving tab stop.",
          "descriptionKey": "ui.agent.toothFindingPalette.actions.focusTool"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "tooth-finding-palette",
          "description": "Marks the palette toolbar wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop. Required to address a specific palette from the agent."
        },
        "item": {
          "attr": "data-condition",
          "description": "Each tool button emits its finding id as data-condition, and the armed tool also carries data-active=\"true\". Group wrappers carry data-group with the group id; the planned/executed pills carry data-status."
        }
      }
    },
    {
      "kind": "component",
      "id": "tooth-scheme",
      "capabilities": [
        "pick",
        "set_value",
        "edit_inline"
      ],
      "state": [
        {
          "name": "chart",
          "type": "Record<FdiId, { conditions: ToothCondition[]; surfaces: Surface[]; symbols: { id?: string; condition: ConditionId; part?: SymbolPart; surfaces?: Surface[]; roots?: Root[]; status?: SymbolStatus; color?: string }[] }>",
          "description": "Current dental chart keyed by FDI id, or by a special-element id (quadrant / sextant / arch / general) for region-spanning findings. Each entry carries the flat `conditions` + `surfaces` pair AND the normalised per-symbol list, where every finding scopes its own surfaces, roots, planned/executed status and colour. Free-text clinical notes are PHI and omitted — read them per tooth via get_symbols / get_notes.",
          "descriptionKey": "ui.agent.toothScheme.state.chart"
        },
        {
          "name": "chartedTeeth",
          "type": "string[]",
          "description": "Ids carrying at least one finding — FDI tooth ids and/or special-element ids (quadrant / sextant / arch / general).",
          "descriptionKey": "ui.agent.toothScheme.state.chartedTeeth"
        },
        {
          "name": "radiographs",
          "type": "Record<string, { id: string; kind?: string }[]>",
          "description": "Structural references (id + kind) to the radiographs on each tooth, keyed by FDI id. Notes, dates and image URLs are not exposed here — fetch them on demand via get_radiographs.",
          "descriptionKey": "ui.agent.toothScheme.state.radiographs"
        },
        {
          "name": "teethWithRadiographs",
          "type": "string[]",
          "description": "FDI ids of every tooth carrying at least one radiograph.",
          "descriptionKey": "ui.agent.toothScheme.state.teethWithRadiographs"
        }
      ],
      "actions": [
        {
          "name": "focus_tooth",
          "safety": "read",
          "argsType": "{ id: FdiId }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "FDI tooth id ('11'–'48' permanent, '51'–'85' primary) or a special-element id ('Q1'–'Q4' quadrants, 'S1'–'S6' sextants, 'AS'/'AI' arches, 'general'; primary mirrors with an 'm' prefix)."
              }
            },
            "required": [
              "id"
            ]
          },
          "idempotent": true,
          "errors": [
            "In the `both` view the registered instance renders no SVG of its own (the four sub-charts do, and deliberately do not register), so this action has no effect there."
          ],
          "description": "Move focus to a specific tooth by FDI id.",
          "descriptionKey": "ui.agent.toothScheme.actions.focusTooth"
        },
        {
          "name": "get_tooth",
          "safety": "read",
          "argsType": "{ id: FdiId }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "FDI tooth id ('11'–'48' permanent, '51'–'85' primary) or a special-element id ('Q1'–'Q4' quadrants, 'S1'–'S6' sextants, 'AS'/'AI' arches, 'general'; primary mirrors with an 'm' prefix)."
              }
            },
            "required": [
              "id"
            ]
          },
          "returns": "ToothCondition[]",
          "returnsSchema": {
            "type": "array",
            "items": {
              "enum": [
                "caries",
                "filled",
                "crowned",
                "temporaryCrown",
                "bridge",
                "missing",
                "implant",
                "implantExtraction",
                "stub",
                "destroyed",
                "rootCanal",
                "pin",
                "rootAmputation",
                "anchorage",
                "hook",
                "attachment",
                "mucogingivalSurgery",
                "periodontalSurgery",
                "curettage",
                "medication",
                "xray"
              ],
              "description": "Built-in finding id. 'destroyed' is the retained root (*radice persistente*); 'xray' is the chartable radiograph SYMBOL, distinct from the image archive reached via get_radiographs."
            }
          },
          "idempotent": true,
          "description": "Read the BUILT-IN findings recorded on one tooth (FDI id), as a flat list of condition ids. Practice-defined findings, per-finding surfaces, roots and status are not included — use get_symbols for the tooth's full record.",
          "descriptionKey": "ui.agent.toothScheme.actions.getTooth"
        },
        {
          "name": "get_symbols",
          "safety": "phi",
          "argsType": "{ id: FdiId }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "FDI tooth id ('11'–'48' permanent, '51'–'85' primary) or a special-element id ('Q1'–'Q4' quadrants, 'S1'–'S6' sextants, 'AS'/'AI' arches, 'general'; primary mirrors with an 'm' prefix)."
              }
            },
            "required": [
              "id"
            ]
          },
          "returns": "ToothSymbol[]",
          "returnsSchema": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "description": "Provenance id — the host's care-plan / finding entry this symbol came from. Present on symbols the host seeded; supply it to update that exact entry."
                },
                "condition": {
                  "type": "string",
                  "description": "Finding id — either a built-in (the enum on set_finding) or a practice-defined id from the host's `conditionRegistry`."
                },
                "part": {
                  "enum": [
                    "element",
                    "surface",
                    "root"
                  ],
                  "description": "Anatomical layer the finding marks. Omit to take the condition's natural part (caries and fillings are 'surface', root canals are 'root', crowns and implants are 'element')."
                },
                "surfaces": {
                  "type": "array",
                  "items": {
                    "enum": [
                      "mesial",
                      "distal",
                      "occlusal",
                      "buccal",
                      "lingual"
                    ],
                    "description": "Tooth surface, named anatomically."
                  }
                },
                "roots": {
                  "type": "array",
                  "items": {
                    "enum": [
                      "mesial",
                      "distal",
                      "palatal",
                      "buccal",
                      "single"
                    ],
                    "description": "Root, named ANATOMICALLY (not by screen side) — 'palatal' exists only on upper molars, 'single' covers every one-rooted tooth. On flank-mounted markers (anchorage, hook) 'mesial' / 'distal' select the side of the tooth instead."
                  }
                },
                "status": {
                  "enum": [
                    "planned",
                    "executed"
                  ],
                  "description": "Execution status — 'planned' (proposed treatment) vs 'executed' (already done). Omit when the finding carries no plan/executed distinction."
                },
                "color": {
                  "type": "string",
                  "description": "Per-practice colour override — a CSS colour or `var(--token)`. Omit to take the condition's own colour."
                },
                "note": {
                  "type": "string",
                  "description": "Free-text clinical note. PHI — never in a state snapshot."
                }
              },
              "required": [
                "condition"
              ]
            }
          },
          "idempotent": true,
          "description": "Read one tooth's full finding record (incl. notes) — one entry per symbol, each with its own surfaces, roots, planned/executed status, colour override, provenance id and free-text note. Normalised, so a tooth charted with the flat conditions/surfaces pair reports the same shape.",
          "descriptionKey": "ui.agent.toothScheme.actions.getSymbols"
        },
        {
          "name": "get_notes",
          "safety": "phi",
          "argsType": "{ id: FdiId }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "FDI tooth id ('11'–'48' permanent, '51'–'85' primary) or a special-element id ('Q1'–'Q4' quadrants, 'S1'–'S6' sextants, 'AS'/'AI' arches, 'general'; primary mirrors with an 'm' prefix)."
              }
            },
            "required": [
              "id"
            ]
          },
          "returns": "string | null",
          "returnsSchema": {
            "type": [
              "string",
              "null"
            ]
          },
          "idempotent": true,
          "description": "Read the tooth-level free-text clinical note, or null when there is none. Per-finding notes are separate — they come back from get_symbols.",
          "descriptionKey": "ui.agent.toothScheme.actions.getNotes"
        },
        {
          "name": "teeth_with",
          "safety": "read",
          "argsType": "{ condition: ToothCondition }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "condition": {
                "enum": [
                  "caries",
                  "filled",
                  "crowned",
                  "temporaryCrown",
                  "bridge",
                  "missing",
                  "implant",
                  "implantExtraction",
                  "stub",
                  "destroyed",
                  "rootCanal",
                  "pin",
                  "rootAmputation",
                  "anchorage",
                  "hook",
                  "attachment",
                  "mucogingivalSurgery",
                  "periodontalSurgery",
                  "curettage",
                  "medication",
                  "xray"
                ],
                "description": "Built-in finding id. 'destroyed' is the retained root (*radice persistente*); 'xray' is the chartable radiograph SYMBOL, distinct from the image archive reached via get_radiographs."
              }
            },
            "required": [
              "condition"
            ]
          },
          "returns": "FdiId[]",
          "returnsSchema": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "FDI tooth id ('11'–'48' permanent, '51'–'85' primary) or a special-element id ('Q1'–'Q4' quadrants, 'S1'–'S6' sextants, 'AS'/'AI' arches, 'general'; primary mirrors with an 'm' prefix)."
            }
          },
          "idempotent": true,
          "description": "List the ids carrying a given built-in finding — FDI tooth ids and/or special-element ids (e.g. all teeth with caries). For a practice-defined finding use teeth_with_symbol.",
          "descriptionKey": "ui.agent.toothScheme.actions.teethWith"
        },
        {
          "name": "teeth_with_symbol",
          "safety": "read",
          "argsType": "{ condition: ConditionId }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "condition": {
                "type": "string",
                "description": "Finding id — either a built-in (the enum on set_finding) or a practice-defined id from the host's `conditionRegistry`."
              }
            },
            "required": [
              "condition"
            ]
          },
          "returns": "FdiId[]",
          "returnsSchema": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "FDI tooth id ('11'–'48' permanent, '51'–'85' primary) or a special-element id ('Q1'–'Q4' quadrants, 'S1'–'S6' sextants, 'AS'/'AI' arches, 'general'; primary mirrors with an 'm' prefix)."
            }
          },
          "idempotent": true,
          "description": "As teeth_with, but open to the practice-defined ids in the host's `conditionRegistry` as well as the built-ins.",
          "descriptionKey": "ui.agent.toothScheme.actions.teethWithSymbol"
        },
        {
          "name": "get_radiographs",
          "safety": "phi",
          "argsType": "{ id: FdiId }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "FDI tooth id ('11'–'48' permanent, '51'–'85' primary) or a special-element id ('Q1'–'Q4' quadrants, 'S1'–'S6' sextants, 'AS'/'AI' arches, 'general'; primary mirrors with an 'm' prefix)."
              }
            },
            "required": [
              "id"
            ]
          },
          "returns": "Radiograph[]",
          "returnsSchema": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "thumbnailUrl": {
                  "type": "string"
                },
                "date": {
                  "type": "string",
                  "description": "ISO acquisition date (YYYY-MM-DD)."
                },
                "note": {
                  "type": "string"
                },
                "kind": {
                  "enum": [
                    "periapical",
                    "bitewing",
                    "panoramic",
                    "other"
                  ]
                },
                "alt": {
                  "type": "string"
                }
              },
              "required": [
                "id",
                "url"
              ]
            }
          },
          "idempotent": true,
          "description": "Read the radiographs (x-rays) attached to one tooth, including their notes, dates and image urls.",
          "descriptionKey": "ui.agent.toothScheme.actions.getRadiographs"
        },
        {
          "name": "open_radiographs",
          "safety": "read",
          "argsType": "{ id: FdiId }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "FDI tooth id ('11'–'48' permanent, '51'–'85' primary) or a special-element id ('Q1'–'Q4' quadrants, 'S1'–'S6' sextants, 'AS'/'AI' arches, 'general'; primary mirrors with an 'm' prefix)."
              }
            },
            "required": [
              "id"
            ]
          },
          "idempotent": true,
          "errors": [
            "In the `both` view the registered instance renders no SVG of its own (the four sub-charts do, and deliberately do not register), so this action has no effect there."
          ],
          "description": "Focus a tooth and open its radiograph archive (fires the host's onOpenRadiographs).",
          "descriptionKey": "ui.agent.toothScheme.actions.openRadiographs"
        },
        {
          "name": "set_finding",
          "safety": "write",
          "argsType": "{ id: FdiId; condition: ToothCondition; surfaces?: Surface[] }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "FDI tooth id ('11'–'48' permanent, '51'–'85' primary) or a special-element id ('Q1'–'Q4' quadrants, 'S1'–'S6' sextants, 'AS'/'AI' arches, 'general'; primary mirrors with an 'm' prefix)."
              },
              "condition": {
                "enum": [
                  "caries",
                  "filled",
                  "crowned",
                  "temporaryCrown",
                  "bridge",
                  "missing",
                  "implant",
                  "implantExtraction",
                  "stub",
                  "destroyed",
                  "rootCanal",
                  "pin",
                  "rootAmputation",
                  "anchorage",
                  "hook",
                  "attachment",
                  "mucogingivalSurgery",
                  "periodontalSurgery",
                  "curettage",
                  "medication",
                  "xray"
                ],
                "description": "Built-in finding id. 'destroyed' is the retained root (*radice persistente*); 'xray' is the chartable radiograph SYMBOL, distinct from the image archive reached via get_radiographs."
              },
              "surfaces": {
                "type": "array",
                "items": {
                  "enum": [
                    "mesial",
                    "distal",
                    "occlusal",
                    "buccal",
                    "lingual"
                  ],
                  "description": "Tooth surface, named anatomically."
                }
              }
            },
            "required": [
              "id",
              "condition"
            ]
          },
          "idempotent": true,
          "description": "Record a built-in finding on a tooth or region element (crown, implant, root canal, caries, …). Optionally mark the affected surfaces for a surface finding. Structural only — to set a finding’s roots, planned/executed status, colour or note, or to chart a practice-defined finding, use set_symbol.",
          "descriptionKey": "ui.agent.toothScheme.actions.setFinding"
        },
        {
          "name": "set_symbol",
          "safety": "phi",
          "argsType": "{ id: FdiId; symbol: ToothSymbol }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "FDI tooth id ('11'–'48' permanent, '51'–'85' primary) or a special-element id ('Q1'–'Q4' quadrants, 'S1'–'S6' sextants, 'AS'/'AI' arches, 'general'; primary mirrors with an 'm' prefix)."
              },
              "symbol": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string",
                    "description": "Provenance id — the host's care-plan / finding entry this symbol came from. Present on symbols the host seeded; supply it to update that exact entry."
                  },
                  "condition": {
                    "type": "string",
                    "description": "Finding id — either a built-in (the enum on set_finding) or a practice-defined id from the host's `conditionRegistry`."
                  },
                  "part": {
                    "enum": [
                      "element",
                      "surface",
                      "root"
                    ],
                    "description": "Anatomical layer the finding marks. Omit to take the condition's natural part (caries and fillings are 'surface', root canals are 'root', crowns and implants are 'element')."
                  },
                  "surfaces": {
                    "type": "array",
                    "items": {
                      "enum": [
                        "mesial",
                        "distal",
                        "occlusal",
                        "buccal",
                        "lingual"
                      ],
                      "description": "Tooth surface, named anatomically."
                    }
                  },
                  "roots": {
                    "type": "array",
                    "items": {
                      "enum": [
                        "mesial",
                        "distal",
                        "palatal",
                        "buccal",
                        "single"
                      ],
                      "description": "Root, named ANATOMICALLY (not by screen side) — 'palatal' exists only on upper molars, 'single' covers every one-rooted tooth. On flank-mounted markers (anchorage, hook) 'mesial' / 'distal' select the side of the tooth instead."
                    }
                  },
                  "status": {
                    "enum": [
                      "planned",
                      "executed"
                    ],
                    "description": "Execution status — 'planned' (proposed treatment) vs 'executed' (already done). Omit when the finding carries no plan/executed distinction."
                  },
                  "color": {
                    "type": "string",
                    "description": "Per-practice colour override — a CSS colour or `var(--token)`. Omit to take the condition's own colour."
                  },
                  "note": {
                    "type": "string",
                    "description": "Free-text clinical note. PHI — never in a state snapshot."
                  }
                },
                "required": [
                  "condition"
                ]
              }
            },
            "required": [
              "id",
              "symbol"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "id": "16",
                "symbol": {
                  "condition": "filled",
                  "surfaces": [
                    "mesial"
                  ],
                  "status": "executed"
                }
              },
              "note": "Record an executed mesial filling on tooth 16, leaving any other finding on that tooth untouched."
            },
            {
              "args": {
                "id": "26",
                "symbol": {
                  "condition": "rootCanal",
                  "roots": [
                    "palatal"
                  ],
                  "status": "planned"
                }
              },
              "note": "Plan a root canal on the palatal root of tooth 26 ('palatal' is the anatomical root, not a screen side)."
            }
          ],
          "description": "Add or replace one finding on a tooth or region element, with its own part, surfaces, roots, planned/executed status, colour override and note. Matched by `symbol.id` when the symbol carries provenance, otherwise by its condition; appended when nothing matches. Accepts practice-defined `conditionRegistry` ids as well as the built-ins.",
          "descriptionKey": "ui.agent.toothScheme.actions.setSymbol"
        },
        {
          "name": "remove_finding",
          "safety": "write",
          "argsType": "{ id: FdiId; condition: ToothCondition }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "FDI tooth id ('11'–'48' permanent, '51'–'85' primary) or a special-element id ('Q1'–'Q4' quadrants, 'S1'–'S6' sextants, 'AS'/'AI' arches, 'general'; primary mirrors with an 'm' prefix)."
              },
              "condition": {
                "enum": [
                  "caries",
                  "filled",
                  "crowned",
                  "temporaryCrown",
                  "bridge",
                  "missing",
                  "implant",
                  "implantExtraction",
                  "stub",
                  "destroyed",
                  "rootCanal",
                  "pin",
                  "rootAmputation",
                  "anchorage",
                  "hook",
                  "attachment",
                  "mucogingivalSurgery",
                  "periodontalSurgery",
                  "curettage",
                  "medication",
                  "xray"
                ],
                "description": "Built-in finding id. 'destroyed' is the retained root (*radice persistente*); 'xray' is the chartable radiograph SYMBOL, distinct from the image archive reached via get_radiographs."
              }
            },
            "required": [
              "id",
              "condition"
            ]
          },
          "idempotent": true,
          "description": "Remove a finding from a tooth — every symbol carrying that condition goes, whatever its surfaces or roots. Built-in ids only.",
          "descriptionKey": "ui.agent.toothScheme.actions.removeFinding"
        },
        {
          "name": "clear_tooth",
          "safety": "destructive",
          "argsType": "{ id: FdiId }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "FDI tooth id ('11'–'48' permanent, '51'–'85' primary) or a special-element id ('Q1'–'Q4' quadrants, 'S1'–'S6' sextants, 'AS'/'AI' arches, 'general'; primary mirrors with an 'm' prefix)."
              }
            },
            "required": [
              "id"
            ]
          },
          "idempotent": true,
          "description": "Clear every finding from a tooth.",
          "descriptionKey": "ui.agent.toothScheme.actions.clearTooth"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "tooth-scheme"
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        },
        "item": {
          "attr": "data-fdi",
          "description": "Each rendered tooth `<g>` carries its FDI id as `data-fdi`, its first finding as `data-condition`, the full space-separated list as `data-conditions`, the finding count as `data-symbol-count` and the first finding's status as `data-status`; selectable special-element slots carry their id in `data-fdi` too (plus `data-special` naming the kind). Per-surface pick targets carry `data-zone`, per-root pick targets `data-root` (the anatomical root name). The `data-projection` / `data-view-mode` attributes on the root expose the side/plan/both view."
        }
      }
    },
    {
      "kind": "component",
      "id": "transaction-chip",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "transaction-chip",
          "description": "Marks the element as a kit TransactionChip."
        }
      }
    },
    {
      "kind": "component",
      "id": "transcript-panel",
      "capabilities": [
        "select_single",
        "copy"
      ],
      "state": [
        {
          "name": "selectedTurn",
          "type": "string | null",
          "description": "Opaque id (line index) of the currently-active turn, or null when none is active.",
          "descriptionKey": "ui.agent.transcriptPanel.state.selectedTurn"
        }
      ],
      "actions": [
        {
          "name": "focus_turn",
          "safety": "read",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              }
            },
            "required": [
              "id"
            ]
          },
          "idempotent": true,
          "description": "Scroll the given turn into view and focus its seek button.",
          "descriptionKey": "ui.agent.transcriptPanel.actions.focusTurn"
        },
        {
          "name": "copy_turn",
          "safety": "write",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              }
            },
            "required": [
              "id"
            ]
          },
          "openWorld": true,
          "description": "Copy the given turn's text to the clipboard.",
          "descriptionKey": "ui.agent.transcriptPanel.actions.copyTurn"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "transcript-panel",
          "description": "Marks the TranscriptPanel wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        },
        "item": {
          "attr": "data-turn-id",
          "description": "Stable opaque turn id (line index). Never carries the turn's dictated text."
        }
      }
    },
    {
      "kind": "component",
      "id": "treatment-receipt",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "treatment-receipt",
          "description": "Marks the element as a kit TreatmentReceipt."
        },
        "item": {
          "attr": "data-treatment-receipt-line",
          "description": "One treatment line."
        }
      }
    },
    {
      "kind": "component",
      "id": "typing-indicator",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "typing-indicator",
          "description": "Marks the element as a kit TypingIndicator."
        }
      }
    },
    {
      "kind": "component",
      "id": "unit-converter",
      "capabilities": [
        "set_value",
        "view_change"
      ],
      "state": [
        {
          "name": "category",
          "type": "'weight' | 'length' | 'temperature' | 'glucose'",
          "description": "Active measurement family. Determines which from/to units are selectable.",
          "descriptionKey": "ui.agent.unitConverter.state.category"
        },
        {
          "name": "inputs",
          "type": "{ value: number | null, fromId: string, toId: string }",
          "description": "Source value plus the from-unit and to-unit ids within the active category.",
          "descriptionKey": "ui.agent.unitConverter.state.inputs"
        },
        {
          "name": "result",
          "type": "number | null",
          "description": "Converted value in the to-unit, or null when the source value is empty.",
          "descriptionKey": "ui.agent.unitConverter.state.result"
        }
      ],
      "actions": [
        {
          "name": "set_value",
          "safety": "write",
          "argsType": "{ value: number | null }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "value": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "Source value to convert, or null to clear."
              }
            },
            "required": [
              "value"
            ]
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "value": 70
              },
              "note": "Convert 70 of the from-unit."
            }
          ],
          "description": "Set the source value to convert.",
          "descriptionKey": "ui.agent.unitConverter.actions.setValue"
        },
        {
          "name": "set_units",
          "safety": "read",
          "argsType": "{ fromId?: string, toId?: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "fromId": {
                "type": "string",
                "description": "Source unit id within the active category."
              },
              "toId": {
                "type": "string",
                "description": "Target unit id within the active category."
              }
            },
            "additionalProperties": false
          },
          "idempotent": true,
          "examples": [
            {
              "args": {
                "fromId": "kg",
                "toId": "lb"
              },
              "note": "Convert kg → lb."
            }
          ],
          "description": "Set the from-unit and/or to-unit. Ids outside the active category are ignored.",
          "descriptionKey": "ui.agent.unitConverter.actions.setUnits"
        },
        {
          "name": "set_category",
          "safety": "read",
          "argsType": "{ category: 'weight' | 'length' | 'temperature' | 'glucose' }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "category": {
                "enum": [
                  "weight",
                  "length",
                  "temperature",
                  "glucose"
                ],
                "description": "Measurement family to switch to."
              }
            },
            "required": [
              "category"
            ]
          },
          "idempotent": true,
          "description": "Switch the measurement family. Resets the from/to units to that category defaults.",
          "descriptionKey": "ui.agent.unitConverter.actions.setCategory"
        },
        {
          "name": "get_result",
          "safety": "read",
          "returns": "number | null",
          "returnsSchema": {
            "type": [
              "number",
              "null"
            ]
          },
          "idempotent": true,
          "description": "Return the converted value in the to-unit, or null when no source value is set.",
          "descriptionKey": "ui.agent.unitConverter.actions.getResult"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "unit-converter",
          "description": "Marks the UnitConverter wrapper."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop. Required to address a specific converter instance."
        }
      }
    },
    {
      "kind": "component",
      "id": "variables-menu",
      "capabilities": [
        "filter",
        "select_single",
        "close"
      ],
      "state": [
        {
          "name": "query",
          "type": "string",
          "description": "Current filter text.",
          "descriptionKey": "ui.agent.variablesMenu.state.query"
        },
        {
          "name": "visibleTokens",
          "type": "string[]",
          "description": "Tokens of the variables currently visible, in row order.",
          "descriptionKey": "ui.agent.variablesMenu.state.visibleTokens"
        }
      ],
      "actions": [
        {
          "name": "select_token",
          "safety": "write",
          "argsType": "{ token: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "token": {
                "type": "string",
                "description": "Token of the variable to insert, without brackets."
              }
            },
            "required": [
              "token"
            ]
          },
          "idempotent": false,
          "examples": [
            {
              "args": {
                "token": "NOME"
              },
              "note": "Insert [[NOME]] and close the menu."
            }
          ],
          "description": "Insert the given variable token at the anchor.",
          "descriptionKey": "ui.agent.variablesMenu.actions.selectToken"
        },
        {
          "name": "close",
          "safety": "read",
          "idempotent": true,
          "description": "Dismiss the menu without inserting anything.",
          "descriptionKey": "ui.agent.variablesMenu.actions.close"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "variables-menu"
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        },
        "item": {
          "attr": "data-variable-token",
          "description": "Each visible row emits its token as data-variable-token."
        }
      }
    },
    {
      "kind": "component",
      "id": "visually-hidden",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "visually-hidden",
          "description": "Marks the element as a kit VisuallyHidden wrapper."
        }
      }
    },
    {
      "kind": "component",
      "id": "voice-control-panel",
      "capabilities": [
        "capture",
        "pick",
        "expand",
        "open",
        "close"
      ],
      "state": [
        {
          "name": "status",
          "type": "'idle' | 'starting' | 'listening' | 'paused' | 'error'",
          "description": "Where the host voice session is: idle, starting, listening, paused or error.",
          "descriptionKey": "ui.agent.voiceControlPanel.state.status"
        },
        {
          "name": "candidateIds",
          "type": "string[]",
          "description": "Ids of the matches currently offered, in spoken order (option 1 first). Empty when there is nothing to choose.",
          "descriptionKey": "ui.agent.voiceControlPanel.state.candidateIds"
        },
        {
          "name": "commandsOpen",
          "type": "boolean",
          "description": "True when the voice commands list is expanded.",
          "descriptionKey": "ui.agent.voiceControlPanel.state.commandsOpen"
        },
        {
          "name": "panelOpen",
          "type": "boolean",
          "description": "Floating layout: true when the panel above the pill is open. Always false inline.",
          "descriptionKey": "ui.agent.voiceControlPanel.state.panelOpen"
        },
        {
          "name": "creditsExhausted",
          "type": "boolean",
          "description": "True when the practice is out of AI credits: every start shows the out-of-credits notice instead of listening.",
          "descriptionKey": "ui.agent.voiceControlPanel.state.creditsExhausted"
        },
        {
          "name": "creditsNoticeOpen",
          "type": "boolean",
          "description": "True when the out-of-credits notice is showing in the panel, in place of the controls.",
          "descriptionKey": "ui.agent.voiceControlPanel.state.creditsNoticeOpen"
        }
      ],
      "actions": [
        {
          "name": "start_listening",
          "safety": "write",
          "idempotent": true,
          "openWorld": true,
          "errors": [
            "Microphone permission denied",
            "Speech service unavailable"
          ],
          "description": "Ask the host to start listening (it opens the microphone). Does nothing when already starting or listening, or while the panel is disabled. Without patient AI consent it shows the consent banner instead; out of AI credits (creditsExhausted) it shows the out-of-credits notice instead.",
          "descriptionKey": "ui.agent.voiceControlPanel.actions.startListening"
        },
        {
          "name": "stop_listening",
          "safety": "write",
          "idempotent": true,
          "description": "Ask the host to stop listening, cancel a start or end a paused session. Never gated by consent or AI credits. Does nothing when idle or stopped.",
          "descriptionKey": "ui.agent.voiceControlPanel.actions.stopListening"
        },
        {
          "name": "pick_candidate",
          "safety": "phi",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "One of the ids in the candidateIds state slot."
              }
            },
            "required": [
              "id"
            ],
            "additionalProperties": false
          },
          "examples": [
            {
              "args": {
                "id": "otve"
              },
              "note": "Pick the match with id otve."
            }
          ],
          "description": "Pick one of the offered matches by id, the same as saying its option number or pressing it. Unknown ids are ignored.",
          "descriptionKey": "ui.agent.voiceControlPanel.actions.pickCandidate"
        },
        {
          "name": "open_commands",
          "safety": "read",
          "idempotent": true,
          "description": "Expand the voice commands list.",
          "descriptionKey": "ui.agent.voiceControlPanel.actions.openCommands"
        },
        {
          "name": "close_commands",
          "safety": "read",
          "idempotent": true,
          "description": "Collapse the voice commands list.",
          "descriptionKey": "ui.agent.voiceControlPanel.actions.closeCommands"
        },
        {
          "name": "open_panel",
          "safety": "read",
          "idempotent": true,
          "description": "Floating layout: open the panel above the pill. Does nothing inline.",
          "descriptionKey": "ui.agent.voiceControlPanel.actions.openPanel"
        },
        {
          "name": "close_panel",
          "safety": "read",
          "idempotent": true,
          "description": "Floating layout: close the panel above the pill. Listening carries on. Does nothing inline.",
          "descriptionKey": "ui.agent.voiceControlPanel.actions.closePanel"
        },
        {
          "name": "close_credits_notice",
          "safety": "read",
          "idempotent": true,
          "description": "Close the out-of-credits notice and go back to the controls. Credits stay out: the next start shows it again.",
          "descriptionKey": "ui.agent.voiceControlPanel.actions.closeCreditsNotice"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "voice-control-panel",
          "description": "Marks the VoiceControlPanel root."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop on VoiceControlPanel."
        },
        "item": {
          "attr": "data-candidate-id",
          "description": "On each match button, the candidate id that pick_candidate takes."
        }
      }
    },
    {
      "kind": "component",
      "id": "wallet-pay-button",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "wallet-pay-button",
          "description": "Marks the branded wallet-pay trigger (Apple Pay / Google Pay). The provider is exposed via data-provider. Payment-flow safety is declared by the host checkout pattern, not this presentational button."
        }
      }
    },
    {
      "kind": "component",
      "id": "warning-stack",
      "capabilities": [
        "dismiss"
      ],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "warning-stack",
          "description": "Marks the WarningStack region. Each item inside is a kit Alert, addressed through the `data-warning-id` on its list row."
        },
        "item": {
          "attr": "data-warning-id",
          "sourceProp": "items[].id",
          "description": "Per-notice identifier sourced from each `WarningStackItem.id` — an opaque notice key, never patient data. Emitted on the rendered `<li>`; the notice’s own dismiss control is the nested `[data-alert-dismiss]` button."
        }
      }
    },
    {
      "kind": "component",
      "id": "whatsapp-button",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "whatsapp-button",
          "description": "Marks the element as a kit WhatsAppButton."
        }
      }
    },
    {
      "kind": "component",
      "id": "widget-picker",
      "capabilities": [
        "pick"
      ],
      "state": [
        {
          "name": "open",
          "type": "boolean",
          "description": "Whether the picker dialog is currently open.",
          "descriptionKey": "ui.agent.widgetPicker.state.open"
        },
        {
          "name": "items",
          "type": "{ id: string, disabled: boolean }[]",
          "description": "Widget-type ids on offer and whether each is pickable. Ids only — titles are host-app strings.",
          "descriptionKey": "ui.agent.widgetPicker.state.items"
        }
      ],
      "actions": [
        {
          "name": "pick_widget",
          "safety": "write",
          "argsType": "id",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "Widget-type id (see items state)."
              }
            },
            "required": [
              "id"
            ]
          },
          "returns": "boolean (accepted)",
          "returnsSchema": {
            "type": "boolean",
            "description": "True when the pick was applied; false when the picker is closed, the id is unknown, or the item is disabled."
          },
          "idempotent": false,
          "description": "Pick a widget type from the open catalogue. The picker closes and the host adds the widget. Refused while the dialog is closed and for disabled items.",
          "descriptionKey": "ui.agent.widgetPicker.actions.pickWidget"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "widget-picker"
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        },
        "item": {
          "attr": "data-widget-type-id",
          "description": "Each option tile carries its widget-type id."
        }
      }
    },
    {
      "kind": "component",
      "id": "workflow-card",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "workflow-card",
          "description": "Marks a Workflow summary card. Presentational — actions are owned by the host pattern."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        }
      }
    },
    {
      "kind": "component",
      "id": "workflow-editor",
      "capabilities": [
        "navigate"
      ],
      "state": [
        {
          "name": "totalSteps",
          "type": "number",
          "description": "Total number of nodes currently in the workflow graph.",
          "descriptionKey": "ui.agent.workflowEditor.state.totalSteps"
        },
        {
          "name": "currentStep",
          "type": "string | null",
          "description": "Opaque node id of the currently-focused step, or null.",
          "descriptionKey": "ui.agent.workflowEditor.state.currentStep"
        }
      ],
      "actions": [
        {
          "name": "goto_step",
          "safety": "read",
          "argsType": "{ id: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              }
            },
            "required": [
              "id"
            ]
          },
          "idempotent": true,
          "description": "Focus a node by its opaque id.",
          "descriptionKey": "ui.agent.workflowEditor.actions.gotoStep"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "workflow-editor",
          "description": "Marks the WorkflowEditor surface."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        },
        "item": {
          "attr": "data-node-id",
          "description": "Stable opaque workflow node id emitted on each node card."
        }
      }
    },
    {
      "kind": "component",
      "id": "workflow-map",
      "capabilities": [],
      "state": [],
      "actions": [],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "workflow-map",
          "description": "Marks a Workflow map (linear visualisation). Presentational."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        },
        "item": {
          "attr": "data-node-id",
          "description": "Stable opaque workflow node id emitted on each step."
        }
      }
    },
    {
      "kind": "component",
      "id": "workflow-status",
      "capabilities": [
        "select_single",
        "set_value",
        "open",
        "close"
      ],
      "state": [
        {
          "name": "value",
          "type": "string",
          "description": "The current non-sensitive workflow status key.",
          "descriptionKey": "ui.agent.workflowStatus.state.value"
        },
        {
          "name": "isOpen",
          "type": "boolean",
          "description": "Whether the permitted workflow status list is open.",
          "descriptionKey": "ui.agent.workflowStatus.state.isOpen"
        },
        {
          "name": "isSaving",
          "type": "boolean",
          "description": "Whether the host is saving a workflow status change.",
          "descriptionKey": "ui.agent.workflowStatus.state.isSaving"
        }
      ],
      "actions": [
        {
          "name": "set_value",
          "safety": "write",
          "argsType": "{ value: string }",
          "argsSchema": {
            "type": "object",
            "properties": {
              "value": {
                "type": "string",
                "description": "Permitted workflow status key to select."
              }
            },
            "required": [
              "value"
            ]
          },
          "idempotent": true,
          "openWorld": true,
          "errors": [
            "The status is not in the host-provided transition list.",
            "The status is disabled.",
            "A status change is already being saved.",
            "The host rejected the change. The previous status stays and the error is shown."
          ],
          "examples": [
            {
              "args": {
                "value": "review"
              }
            }
          ],
          "description": "Request a permitted workflow status through the host-owned change callback.",
          "descriptionKey": "ui.agent.workflowStatus.actions.setValue"
        },
        {
          "name": "open",
          "safety": "read",
          "idempotent": true,
          "description": "Open the permitted workflow status list.",
          "descriptionKey": "ui.agent.workflowStatus.actions.open"
        },
        {
          "name": "close",
          "safety": "read",
          "idempotent": true,
          "description": "Close the workflow status list.",
          "descriptionKey": "ui.agent.workflowStatus.actions.close"
        }
      ],
      "domHooks": {
        "root": {
          "attr": "data-component",
          "value": "workflow-status",
          "description": "Marks the WorkflowStatus boundary."
        },
        "instanceId": {
          "attr": "data-component-id",
          "sourceProp": "id",
          "description": "Sourced from the id prop."
        },
        "item": {
          "attr": "data-option-id",
          "description": "Non-sensitive workflow status key for a permitted option."
        }
      }
    }
  ],
  "patterns": [
    {
      "kind": "pattern",
      "id": "alia-assistant",
      "composes": [
        {
          "component": "chat-container",
          "as": "conversation",
          "entity": "message"
        },
        {
          "component": "chat-message",
          "as": "message",
          "entity": "message"
        },
        {
          "component": "streaming-text",
          "as": "streamingReply"
        },
        {
          "component": "typing-indicator",
          "as": "typing"
        },
        {
          "component": "suggestion-chip",
          "as": "suggestion",
          "entity": "suggestion"
        },
        {
          "component": "chat-input",
          "as": "composer"
        },
        {
          "component": "avatar",
          "as": "assistantAvatar"
        },
        {
          "component": "progress",
          "as": "usageMeter"
        },
        {
          "component": "sheet",
          "as": "popoutPanel"
        }
      ],
      "workflows": [
        {
          "name": "send_message",
          "safety": "write",
          "description": "Type a question into the composer and send it; Alia streams a reply into the conversation.",
          "descriptionKey": "ui.agent.aliaAssistant.workflows.sendMessage",
          "uiActions": [
            "chat-input.set_value",
            "chat-input.submit"
          ],
          "stateReads": [
            "chat-input.value",
            "chat-input.isEmpty"
          ],
          "apiActions": [
            "alia.sendMessage"
          ]
        },
        {
          "name": "pick_suggestion",
          "safety": "write",
          "description": "Send one of the suggested prompts as the next user message.",
          "descriptionKey": "ui.agent.aliaAssistant.workflows.pickSuggestion",
          "uiActions": [
            "suggestion-chip.select"
          ],
          "apiActions": [
            "alia.sendMessage"
          ]
        },
        {
          "name": "stop_generating",
          "safety": "write",
          "description": "Cancel the in-flight streaming response while Alia is generating.",
          "descriptionKey": "ui.agent.aliaAssistant.workflows.stopGenerating",
          "uiActions": [],
          "apiActions": [
            "alia.cancelGeneration"
          ]
        },
        {
          "name": "retry_message",
          "safety": "write",
          "description": "Re-send a message that failed to send. The failed message is located by its `data-status=\"error\"` ChatMessage (addressed via `data-component-id`); activating that message's built-in retry control re-submits it. No adapter action — the retry control is a DOM-click affordance on the errored message.",
          "descriptionKey": "ui.agent.aliaAssistant.workflows.retryMessage",
          "uiActions": [],
          "apiActions": [
            "alia.sendMessage"
          ]
        },
        {
          "name": "toggle_popout",
          "safety": "read",
          "description": "Open or close the floating Alia popout panel (FAB + Sheet) over the current page.",
          "descriptionKey": "ui.agent.aliaAssistant.workflows.togglePopout",
          "uiActions": [
            "sheet.open",
            "sheet.close",
            "sheet.dismiss"
          ],
          "stateReads": [
            "sheet.isOpen"
          ],
          "apiActions": []
        },
        {
          "name": "scroll_to_latest",
          "safety": "read",
          "description": "Scroll the conversation log to the newest message.",
          "descriptionKey": "ui.agent.aliaAssistant.workflows.scrollToLatest",
          "uiActions": [
            "chat-container.scroll_to_bottom"
          ],
          "apiActions": []
        },
        {
          "name": "review_usage",
          "safety": "read",
          "description": "Read the assistant usage meter; when the quota is full the composer locks behind an upgrade CTA.",
          "descriptionKey": "ui.agent.aliaAssistant.workflows.reviewUsage",
          "uiActions": [],
          "apiActions": [
            "alia.getUsage",
            "alia.upgradePlan"
          ]
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "anamnesis",
      "composes": [
        {
          "component": "tabs",
          "as": "recordViews"
        },
        {
          "component": "accordion",
          "as": "intakeSections"
        },
        {
          "component": "progress",
          "as": "intakeProgress"
        },
        {
          "component": "form-field",
          "as": "field",
          "entity": "answer"
        },
        {
          "component": "radio-group",
          "as": "yesNoAnswer"
        },
        {
          "component": "text-input",
          "as": "textAnswer"
        },
        {
          "component": "text-area",
          "as": "freeText"
        },
        {
          "component": "number-input",
          "as": "measurement",
          "entity": "parameter"
        },
        {
          "component": "time-picker",
          "as": "mealTime",
          "entity": "meal"
        },
        {
          "component": "select",
          "as": "picker"
        },
        {
          "component": "multi-select",
          "as": "pathologies",
          "entity": "pathology"
        },
        {
          "component": "collapsible",
          "as": "fullQuestionnaire"
        },
        {
          "component": "collapsible",
          "as": "intakeGaps"
        },
        {
          "component": "sparkline",
          "as": "trend",
          "entity": "parameter"
        },
        {
          "component": "description-list",
          "as": "readOnlyValues"
        },
        {
          "component": "popover",
          "as": "visitNote",
          "entity": "visit"
        },
        {
          "component": "popover",
          "as": "targetEditor",
          "entity": "parameter"
        },
        {
          "component": "dropdown-menu",
          "as": "shownVisits",
          "entity": "visit"
        },
        {
          "component": "dropdown-menu",
          "as": "exportMenu"
        },
        {
          "component": "dialog",
          "as": "sharePreview"
        },
        {
          "component": "radio-group",
          "as": "shareAudience"
        },
        {
          "component": "alert",
          "as": "missingAnswers"
        },
        {
          "component": "alert",
          "as": "sharePreviewNotice"
        },
        {
          "component": "empty-state",
          "as": "emptyRecord"
        },
        {
          "component": "card",
          "as": "block"
        },
        {
          "component": "badge",
          "as": "status"
        },
        {
          "component": "button",
          "as": "action"
        },
        {
          "component": "icon-button",
          "as": "removeAction"
        },
        {
          "component": "timestamp",
          "as": "visitDate"
        }
      ],
      "workflows": [
        {
          "name": "start_intake",
          "safety": "phi",
          "description": "Open a fresh pre-visit questionnaire for the patient to begin the intake interview.",
          "descriptionKey": "ui.agent.anamnesis.workflows.startIntake",
          "uiActions": [],
          "apiActions": [
            "anamnesis.create"
          ]
        },
        {
          "name": "navigate_section",
          "safety": "read",
          "description": "Move between questionnaire sections in the intake, reading the current section index.",
          "descriptionKey": "ui.agent.anamnesis.workflows.navigateSection",
          "uiActions": [
            "accordion.expand"
          ],
          "stateReads": [
            "accordion.openItems"
          ],
          "apiActions": []
        },
        {
          "name": "save_intake",
          "safety": "phi",
          "description": "Persist the patient's questionnaire answers. Writes patient-identifiable clinical history.",
          "descriptionKey": "ui.agent.anamnesis.workflows.saveIntake",
          "uiActions": [],
          "apiActions": [
            "anamnesis.updateAnswers"
          ]
        },
        {
          "name": "select_view",
          "safety": "read",
          "description": "Switch the diagnostic workspace between the read-only summary of the patient's questionnaire, the current-visit compile view and the across-visits evolution view. The summary is selected on arrival.",
          "descriptionKey": "ui.agent.anamnesis.workflows.selectView",
          "uiActions": [
            "tabs.select_tab"
          ],
          "stateReads": [
            "tabs.activeTab"
          ],
          "apiActions": []
        },
        {
          "name": "record_measurement",
          "safety": "phi",
          "description": "Record or correct an anthropometric, dietary-intake (daily energy, protein) or blood-test value for the current visit. BMI is computed from weight and height and cannot be recorded. Writes patient clinical data.",
          "descriptionKey": "ui.agent.anamnesis.workflows.recordMeasurement",
          "uiActions": [
            "number-input.set_value"
          ],
          "apiActions": [
            "anamnesis.updateVisit"
          ]
        },
        {
          "name": "set_target",
          "safety": "phi",
          "description": "Set or clear the patient's target for one parameter. Every parameter the practice tracks as a goal is set from the summary strip at the top of the Diagnosis surface — the kit seeds target weight, target BMI, daily energy and protein, and a practice can track any numeric parameter it flags as a goal; a targetable parameter that is not tracked (waist, by default) is set from its capture block, through the same editor. Each tile's edit button opens a small form: nothing is committed until Save, a value outside the parameter's sane range is refused rather than silently clamped, and Clear removes the goal rather than setting it to zero. A target belongs to the record, not to a visit — setting one records no measurement. Writes patient clinical data.",
          "descriptionKey": "ui.agent.anamnesis.workflows.setTarget",
          "uiActions": [
            "popover.open",
            "popover.close",
            "number-input.set_value"
          ],
          "stateReads": [
            "popover.isOpen"
          ],
          "apiActions": [
            "anamnesis.updateTargets"
          ]
        },
        {
          "name": "assign_pathologies",
          "safety": "phi",
          "description": "Assign or remove coded pathologies for the current visit via the multi-select, reading the current assignments.",
          "descriptionKey": "ui.agent.anamnesis.workflows.assignPathologies",
          "uiActions": [
            "multi-select.set_selection"
          ],
          "stateReads": [
            "multi-select.selection"
          ],
          "apiActions": [
            "anamnesis.updatePathologies"
          ]
        },
        {
          "name": "read_intake_digest",
          "safety": "read",
          "description": "Read the Summary tab: the at-a-glance digest of the patient's questionnaire — why they came, the conditions and medication they carry, the symptoms they report and their daily habits — and, one disclosure below it, the full answer list with its from-patient origin markers. Read-only; clinician-only; no mutation.",
          "descriptionKey": "ui.agent.anamnesis.workflows.readIntakeDigest",
          "uiActions": [
            "tabs.select_tab",
            "collapsible.toggle"
          ],
          "stateReads": [
            "tabs.activeTab",
            "collapsible.isOpen"
          ],
          "apiActions": []
        },
        {
          "name": "resolve_missing_answers",
          "safety": "phi",
          "description": "Read how many required questionnaire answers are still missing, jump to the first of them — which crosses from the read-only Summary to the Compile tab and opens the unanswered-questions block that holds it — and record the answer there. Writes patient clinical history.",
          "descriptionKey": "ui.agent.anamnesis.workflows.resolveMissingAnswers",
          "uiActions": [
            "tabs.select_tab",
            "accordion.expand",
            "collapsible.open",
            "text-input.set_value",
            "radio-group.set_value"
          ],
          "stateReads": [
            "tabs.activeTab",
            "accordion.openItems",
            "collapsible.isOpen"
          ],
          "apiActions": [
            "anamnesis.updateAnswers"
          ]
        },
        {
          "name": "read_visit_note",
          "safety": "read",
          "description": "Open the note recorded at one visit from the evolution grid's visit-column header and read the clinical note and the nutritional proposal. Where the host supplies a side panel (`onOpenNote`), the trigger hands that visit's id out and the host's panel navigates to it — no popover opens, and the note lives in exactly one place. Where it does not, the same trigger opens the note in place. Clinician-only; no mutation.",
          "descriptionKey": "ui.agent.anamnesis.workflows.readVisitNote",
          "uiActions": [
            "popover.open",
            "popover.close"
          ],
          "stateReads": [
            "popover.isOpen"
          ],
          "apiActions": []
        },
        {
          "name": "open_record_section",
          "safety": "read",
          "description": "Open or fold one section of the compile form. Sections filled at every visit start open — visit details, any unanswered required questionnaire answers, anthropometrics, pathologies, therapy, the proposal; the occasional ones (oncological history, blood tests, fasting cycles, annual programme) start folded and state in their header how many entries they already hold. Clinician-only; view state only.",
          "descriptionKey": "ui.agent.anamnesis.workflows.openRecordSection",
          "uiActions": [
            "collapsible.toggle"
          ],
          "stateReads": [
            "collapsible.isOpen"
          ],
          "apiActions": []
        },
        {
          "name": "window_visits",
          "safety": "read",
          "description": "Choose which visits the evolution grid shows as columns, by ticking them in the Visits menu — one button that opens a list of checkbox items, with a Select all row first. Every visit is ticked on arrival; un-ticking one removes its column, the menu stays open while ticking, and the last remaining visit cannot be un-ticked. The change between two adjacent shown columns is always drawn. The button itself reads how many visits are shown out of how many exist. Clinician-only; view state only.",
          "descriptionKey": "ui.agent.anamnesis.workflows.windowVisits",
          "uiActions": [
            "dropdown-menu.open",
            "dropdown-menu.close"
          ],
          "stateReads": [
            "dropdown-menu.isOpen"
          ],
          "apiActions": []
        },
        {
          "name": "annotate_trend",
          "safety": "read",
          "description": "Drop a dated event's reference line across every trend sparkline in the evolution grid, by pressing its chip in the event bar above the grid. Events are things that happened to the patient on a date — a therapy or diet starting, a fasting-mimicking cycle, surgery, a change in daily life — and need not have happened at a visit or been recorded by this practice. Each chip carries its category (and, for an event this practice did not record, its source) as an accessible description rather than a hover tooltip. Nothing is drawn on arrival; pressing the same chip again removes the line. Where the host supplies a side panel, turning a chip on also navigates that panel to the event; turning it off does not. Clinician-only; view state only.",
          "descriptionKey": "ui.agent.anamnesis.workflows.annotateTrend",
          "uiActions": [],
          "apiActions": []
        },
        {
          "name": "choose_export_audience",
          "safety": "read",
          "description": "Choose who a file or a shared copy is for — the practice, or the patient — from the single Export & share control beside the view switch. The choice governs every route below it (share, PDF, print, Excel, CSV), it sticks across tabs and later exports, and a non-default choice is badged on the closed control. The menu names what the copy carries in BOTH states, and the exclusions are PER VIEW: on Compile a patient copy drops blood-test values, diagnostic codes, oncological history and the clinician's own notes; on Evolution it drops the blood-test rows; on Summary it drops nothing. Nothing is filed by making the choice. View state only.",
          "descriptionKey": "ui.agent.anamnesis.workflows.chooseExportAudience",
          "uiActions": [
            "dropdown-menu.open",
            "dropdown-menu.close"
          ],
          "stateReads": [
            "dropdown-menu.isOpen"
          ],
          "apiActions": []
        },
        {
          "name": "export_tab",
          "safety": "phi",
          "description": "Produce a file of the view that is currently selected — Summary, Compile or Evolution — from the one Export & share control. The same document is written as a PDF, an Excel workbook or a CSV, and Print sends that same document to the printer rather than the screen, so the app shell never appears on the page. On Evolution the file follows the visit columns the grid is DRAWING unless \"include every visit\" is ticked; the same Evolution file is also offered from the trend tab of questionnaire mode and from the read-only record, at the end of the trend toolbar. The audience rides in the filename, so the two copies stay apart outside the app. Every table resolves through the patient-copy boundary first, so a patient-audience file is missing what that audience may not receive. Produces a patient-identifiable document.",
          "descriptionKey": "ui.agent.anamnesis.workflows.exportTab",
          "uiActions": [
            "dropdown-menu.open",
            "dropdown-menu.close"
          ],
          "stateReads": [
            "dropdown-menu.isOpen"
          ],
          "apiActions": [
            "anamnesis.exportTab"
          ]
        },
        {
          "name": "preview_share",
          "safety": "read",
          "description": "Open the share preview for the selected view, choose the recipient, and read what that recipient's copy would hold and what it would leave out. THIS SENDS NOTHING: the dialog is a preview of the shape of a share. Real delivery — a signed expiring link, the consent gate, and the record of who received what over which channel — is not part of this surface. Confirming only sets the recipient the next export uses. No mutation, no transmission.",
          "descriptionKey": "ui.agent.anamnesis.workflows.previewShare",
          "uiActions": [
            "dialog.open",
            "dialog.close",
            "dialog.dismiss",
            "radio-group.set_value"
          ],
          "stateReads": [
            "dialog.isOpen",
            "radio-group.value"
          ],
          "apiActions": []
        },
        {
          "name": "review_record",
          "safety": "read",
          "description": "Review a completed anamnesis in the care plan: expand the intake answers and read the record. No mutation.",
          "descriptionKey": "ui.agent.anamnesis.workflows.reviewRecord",
          "uiActions": [
            "collapsible.toggle"
          ],
          "apiActions": [
            "anamnesis.get"
          ]
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "appointments",
      "composes": [
        {
          "component": "data-table",
          "as": "agenda",
          "entity": "appointment"
        },
        {
          "component": "warning-stack",
          "as": "alertsStrip",
          "entity": "notice"
        },
        {
          "component": "card",
          "as": "gridShell"
        },
        {
          "component": "icon-button-group",
          "as": "toolbar"
        },
        {
          "component": "icon-button",
          "as": "toolbarAction"
        },
        {
          "component": "button",
          "as": "rowAction"
        },
        {
          "component": "switch",
          "as": "groupByOperator"
        },
        {
          "component": "smart-date",
          "as": "apptDate"
        },
        {
          "component": "counter",
          "as": "treatmentCount"
        },
        {
          "component": "whatsapp-button",
          "as": "contactPatient"
        }
      ],
      "workflows": [
        {
          "name": "filter_appointments",
          "safety": "read",
          "description": "Narrow the agenda by date range, patient, operator, chair, type, or status using the per-column filters.",
          "descriptionKey": "ui.agent.appointments.workflows.filterAppointments",
          "uiActions": [
            "data-table.apply_filter"
          ],
          "stateReads": [
            "data-table.filter"
          ],
          "apiActions": [
            "appointment.list"
          ]
        },
        {
          "name": "group_by_operator",
          "safety": "read",
          "description": "Toggle the \"group by operator\" view so appointments nest under their booked clinician.",
          "descriptionKey": "ui.agent.appointments.workflows.groupByOperator",
          "uiActions": [
            "switch.set_checked"
          ],
          "stateReads": [
            "switch.checked"
          ],
          "apiActions": []
        },
        {
          "name": "add_treatment",
          "safety": "write",
          "description": "Add a treatment line to an appointment from its row action menu.",
          "descriptionKey": "ui.agent.appointments.workflows.addTreatment",
          "uiActions": [
            "data-table.get_selection"
          ],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": [
            "appointment.addTreatment"
          ]
        },
        {
          "name": "reschedule_appointment",
          "safety": "write",
          "description": "Move an open appointment to a new slot via its row \"Reschedule\" action. Closed (done / absent / cancelled) appointments cannot be rescheduled.",
          "descriptionKey": "ui.agent.appointments.workflows.rescheduleAppointment",
          "uiActions": [
            "data-table.get_selection"
          ],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": [
            "appointment.reschedule"
          ]
        },
        {
          "name": "cancel_appointment",
          "safety": "destructive",
          "description": "Cancel an open appointment via its row \"Cancel appointment\" action. Destructive — frees the chair and drops the booking.",
          "descriptionKey": "ui.agent.appointments.workflows.cancelAppointment",
          "uiActions": [
            "data-table.get_selection"
          ],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": [
            "appointment.cancel"
          ]
        },
        {
          "name": "execute_treatment",
          "safety": "write",
          "description": "Mark a planned treatment line as done from its line action menu.",
          "descriptionKey": "ui.agent.appointments.workflows.executeTreatment",
          "uiActions": [
            "data-table.get_selection"
          ],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": [
            "treatment.execute"
          ]
        },
        {
          "name": "contact_patient",
          "safety": "write",
          "description": "Message the patient on WhatsApp from the appointment row (e.g. send a confirmation reminder).",
          "descriptionKey": "ui.agent.appointments.workflows.contactPatient",
          "uiActions": [],
          "apiActions": [
            "patient.messageWhatsApp"
          ]
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "calendar",
      "composes": [
        {
          "component": "calendar",
          "as": "agenda",
          "entity": "appointment"
        },
        {
          "component": "card",
          "as": "page"
        },
        {
          "component": "scroll-area",
          "as": "surfaceScroller"
        },
        {
          "component": "visually-hidden",
          "as": "dockAnnouncement"
        },
        {
          "component": "control-room-rail",
          "as": "toolRail"
        },
        {
          "component": "icon-button",
          "as": "newAppointment"
        },
        {
          "component": "icon-button",
          "as": "waitingListSplit"
        },
        {
          "component": "icon-button",
          "as": "onlineBookings"
        },
        {
          "component": "icon-button",
          "as": "findFreeSlots"
        },
        {
          "component": "popover",
          "as": "chairFilter"
        },
        {
          "component": "checkbox",
          "as": "chairChoice",
          "entity": "chair"
        },
        {
          "component": "popover",
          "as": "operatorFilter"
        },
        {
          "component": "checkbox",
          "as": "operatorChoice",
          "entity": "operator"
        },
        {
          "component": "avatar",
          "as": "operatorFace",
          "entity": "operator"
        },
        {
          "component": "tag",
          "as": "disabledOperatorMarker",
          "entity": "operator"
        },
        {
          "component": "switch",
          "as": "availableOperatorsOnly"
        },
        {
          "component": "switch",
          "as": "showDisabledOperators"
        },
        {
          "component": "badge",
          "as": "filterCount"
        },
        {
          "component": "button",
          "as": "resetFilters"
        },
        {
          "component": "icon-button",
          "as": "toolbarIcon"
        },
        {
          "component": "dropdown-menu",
          "as": "displaySettings"
        },
        {
          "component": "date-picker",
          "as": "jumpToDate"
        },
        {
          "component": "dropdown-menu",
          "as": "viewMenu"
        },
        {
          "component": "kbd",
          "as": "rangeShortcutHint"
        },
        {
          "component": "button-group",
          "as": "rangeNav"
        },
        {
          "component": "popover",
          "as": "hoverPeek",
          "entity": "appointment"
        },
        {
          "component": "key-value-pair",
          "as": "peekFact"
        },
        {
          "component": "timestamp",
          "as": "peekTime"
        },
        {
          "component": "dialog",
          "as": "moveConfirm"
        },
        {
          "component": "checkbox",
          "as": "notifyChannel"
        },
        {
          "component": "radio-group",
          "as": "moveScope"
        },
        {
          "component": "radio",
          "as": "scopeOption"
        },
        {
          "component": "dialog",
          "as": "printDayPicker"
        },
        {
          "component": "data-table",
          "as": "callSheet",
          "entity": "appointment"
        },
        {
          "component": "toast",
          "as": "feedback"
        },
        {
          "component": "appointment-timeline",
          "as": "upcoming",
          "entity": "appointment"
        },
        {
          "component": "panel-header",
          "as": "panelHeader"
        },
        {
          "component": "empty-state",
          "as": "emptyPanel"
        },
        {
          "component": "form-field",
          "as": "formRow"
        },
        {
          "component": "radio-group",
          "as": "appointmentType"
        },
        {
          "component": "combobox",
          "as": "patientPicker",
          "entity": "patient"
        },
        {
          "component": "combobox",
          "as": "carePicker",
          "entity": "care"
        },
        {
          "component": "combobox",
          "as": "durationPicker"
        },
        {
          "component": "select",
          "as": "operatorSelect",
          "entity": "operator"
        },
        {
          "component": "select",
          "as": "chairSelect",
          "entity": "chair"
        },
        {
          "component": "select",
          "as": "branchSelect",
          "entity": "branch"
        },
        {
          "component": "select",
          "as": "statusSelect"
        },
        {
          "component": "date-picker",
          "as": "appointmentDate"
        },
        {
          "component": "time-picker",
          "as": "startTime"
        },
        {
          "component": "color-picker",
          "as": "appointmentColour"
        },
        {
          "component": "text-input",
          "as": "appointmentDescription"
        },
        {
          "component": "number-input",
          "as": "repetitionCount"
        },
        {
          "component": "checkbox",
          "as": "reminderChannel"
        },
        {
          "component": "radio-group",
          "as": "requiredDocsSignMode"
        },
        {
          "component": "alert",
          "as": "editorAdvisory"
        },
        {
          "component": "tag",
          "as": "careRowMarker",
          "entity": "care"
        },
        {
          "component": "icon-button-group",
          "as": "panelToolbar"
        },
        {
          "component": "icon-button",
          "as": "panelAction"
        },
        {
          "component": "timeline",
          "as": "modificationHistory"
        },
        {
          "component": "appointment-details-panel",
          "as": "appointmentDetails",
          "entity": "appointment"
        },
        {
          "component": "task-editor",
          "as": "taskEditor",
          "entity": "task"
        },
        {
          "component": "notes-panel",
          "as": "patientNotes",
          "entity": "note"
        },
        {
          "component": "dialog",
          "as": "noteDeleteConfirm"
        },
        {
          "component": "dialog",
          "as": "deleteConfirm"
        },
        {
          "component": "radio-group",
          "as": "deleteScope"
        },
        {
          "component": "radio-group",
          "as": "seriesScope"
        },
        {
          "component": "button",
          "as": "seriesScopeChange"
        },
        {
          "component": "dropdown-menu",
          "as": "signatureMenu"
        },
        {
          "component": "signature-status-chip",
          "as": "signatureStatus"
        },
        {
          "component": "key-value-pair",
          "as": "readOnlyFact"
        },
        {
          "component": "select",
          "as": "waitingQuickView"
        },
        {
          "component": "button",
          "as": "advancedFilterToggle"
        },
        {
          "component": "badge",
          "as": "waitingFilterCount"
        },
        {
          "component": "avatar",
          "as": "waitingPatientFace",
          "entity": "patient"
        },
        {
          "component": "whatsapp-button",
          "as": "whatsAppLink",
          "entity": "patient"
        },
        {
          "component": "icon-button",
          "as": "waitingRowAction",
          "entity": "waitingEntry"
        },
        {
          "component": "appointment-card",
          "as": "bookingRow",
          "entity": "appointment"
        },
        {
          "component": "dropdown-menu",
          "as": "backlogSettings"
        },
        {
          "component": "collapsible",
          "as": "finderFilters"
        },
        {
          "component": "popover",
          "as": "finderScope"
        },
        {
          "component": "checkbox",
          "as": "finderScopeChoice"
        },
        {
          "component": "switch",
          "as": "finderToggle"
        },
        {
          "component": "select",
          "as": "medicalDeviceSelect"
        },
        {
          "component": "alert",
          "as": "finderAdvisory"
        }
      ],
      "workflows": [
        {
          "name": "browse_agenda",
          "safety": "read",
          "description": "Navigate the agenda: today, previous / next range, jump to a date through the navigation row's date picker, or change what the grid shows from the one view menu — a range (day, three days, week, month, also reachable as the bare keys D · X · W · M) and a column axis (plain, chairs, operators), plus a remembered \"Show weekends\" item that hides Saturday and Sunday in every range. Each range change hands the new window to the host, which fetches the appointments for it.",
          "descriptionKey": "ui.agent.calendar.workflows.browseAgenda",
          "uiActions": [
            "calendar.today",
            "calendar.prev",
            "calendar.next",
            "calendar.goto_date",
            "calendar.change_view",
            "date-picker.set_date",
            "dropdown-menu.open",
            "dropdown-menu.close"
          ],
          "stateReads": [
            "calendar.currentView",
            "calendar.currentDate",
            "calendar.currentTitle",
            "date-picker.value",
            "dropdown-menu.isOpen"
          ],
          "apiActions": [
            "appointment.list"
          ]
        },
        {
          "name": "filter_columns",
          "safety": "read",
          "description": "Narrow the grid to particular chairs or operators from the two filter popovers, with the platform's semantics: nothing ticked shows everyone and ticking narrows. Operators list under their groups with a tri-state row per group; \"Only available operators\" is on by default in the operator views, and a session-local \"Show disabled operators\" switch reveals the operators the practice has disabled. A count badge rides each filter button while it narrows, and the \"Reset filters\" chip beside them clears both selections and restores both switches without ever changing the view. Selection only — no appointment is touched.",
          "descriptionKey": "ui.agent.calendar.workflows.filterColumns",
          "uiActions": [
            "popover.open",
            "popover.close",
            "checkbox.set_checked",
            "checkbox.toggle",
            "switch.set_checked",
            "switch.toggle"
          ],
          "stateReads": [
            "popover.isOpen",
            "checkbox.checked",
            "switch.checked"
          ],
          "apiActions": []
        },
        {
          "name": "mask_patient_names",
          "safety": "read",
          "description": "Turn privacy mode on or off from the toolbar. While on, patient identity is masked across the grid and the whole rail: the cards, the hover peek, the Appointments panel, the appointment details panel (patient card, description, booking contact, notes preview and the WhatsApp link are hidden), the online bookings, the waiting list and the printed call sheet; the Notes tool and the edit form show a notice instead of their content, and so does a tool the host adds, unless the host masks it itself. The page can stay open beside a waiting patient. It is a display mask, not a permission: it is not persisted and it changes no record.",
          "descriptionKey": "ui.agent.calendar.workflows.maskPatientNames",
          "uiActions": [],
          "apiActions": []
        },
        {
          "name": "configure_display",
          "safety": "write",
          "description": "Set the per-user display knobs in the cog's settings menu (each setting's row shows its current value and opens a submenu of options; on/off settings are switch rows; the last item resets to the defaults) — layout, zebra rows, show times, slot precision, the day window, the care-description mode, what the cards are coloured by, the default duration of a new appointment (a preset from 10 to 60 minutes, or the value already saved), whether operators read as an initials disc or a dot plus full name, whether chairs read as a full name or a short code, whether the details panel offers the map link, the row density (compact or comfortable), the colour strength of the cards (tinted or solid), and whether cards show the operator or chair from the other axis. The same menu holds the appointment icon legend as a submenu. An agent drives the menu with instance id calendar-display-settings: set_value with a choice row's name (orientation, slotDensity, window, slotDuration, eventColorStyle, colorAssociation, careDescription, operatorNameDisplay, chairNameDisplay, defaultDurationMin) and one of its option values, or set_checked with a switch row's name (zebraRows, showTime, showCardContext, mapsLink); the menu opens for the moment when closed. The settings state lists each row's name, value and options while the menu is open. The choices are remembered per user through the host's preferences adapter under `calendarWorkspace.*` keys, so they persist beyond the page load; they change presentation only and touch no patient record.",
          "descriptionKey": "ui.agent.calendar.workflows.configureDisplay",
          "uiActions": [
            "dropdown-menu.open",
            "dropdown-menu.close",
            "dropdown-menu.set_value",
            "dropdown-menu.set_checked"
          ],
          "stateReads": [
            "dropdown-menu.isOpen",
            "dropdown-menu.settings"
          ],
          "apiActions": [
            "calendarPreference.update"
          ]
        },
        {
          "name": "dock_tool",
          "safety": "read",
          "description": "Open a workspace rail tool: Appointments, appointment editor / details, waiting list, patient notes, online bookings or free-slot finder. Read the actual strip: hosts may withhold tools, and patient-notes is registered only with patient context. Notes uses the host's note permissions, independently of appointment-edit rights. Clearing its patient context returns to the previous available tool and focuses its rail button. Opening notes from a panel may address a note id and moves focus into Notes. Closing other tools returns to Appointments. A host may add its own tools after these; they carry the host's ids, so read the strip's data-tool-id before opening one. open ignores an id no tool carries; select_tool with one, or a host tool the host withdraws while open, docks Appointments. patient-notes is the exception: withheld or without a patient, it returns to the previous tool, unannounced.",
          "descriptionKey": "ui.agent.calendar.workflows.dockTool",
          "uiActions": [
            "control-room-rail.open",
            "control-room-rail.close",
            "control-room-rail.select_tool"
          ],
          "stateReads": [
            "control-room-rail.activeToolId"
          ],
          "apiActions": []
        },
        {
          "name": "review_upcoming",
          "safety": "read",
          "description": "Read the rail's resting panel: the practice's upcoming appointments — now to the end of the seventh day, cancelled excluded, earliest first — each row led by the patient. The preset row, the jump-to-date picker and the edge loaders widen the derived window up to ±180 days. Activating a row selects that appointment on the grid, which docks its details. Read-only; the rows carry ids and lifecycle state, never patient identity.",
          "descriptionKey": "ui.agent.calendar.workflows.reviewUpcoming",
          "uiActions": [
            "appointment-timeline.select_item",
            "appointment-timeline.jump_to_today",
            "date-picker.set_date",
            "calendar.focus_event"
          ],
          "stateReads": [
            "appointment-timeline.items",
            "date-picker.value"
          ],
          "apiActions": [
            "appointment.list"
          ]
        },
        {
          "name": "read_appointment_details",
          "safety": "phi",
          "description": "Read one appointment in the docked details panel (appointment-details-panel). With the host's details read, any card click, including a patient-less block and a chip whose names are still loading, focuses the appointment and docks a read-only panel: appointment, booking, money, contact, treatments, signing and series sections, the patient's latest three notes and a History sub-view. See more or a note opens the separate Notes rail tool when the host offers it. While the read is loading, failed or refused the panel shows that status instead. Edit, withheld from a read-only viewer, opens the editor. Without the host's read a pending chip stays inert and the editor form is the details. Reads patient-identifiable data.",
          "descriptionKey": "ui.agent.calendar.workflows.readAppointmentDetails",
          "uiActions": [
            "calendar.focus_event",
            "appointment-details-panel.open_history",
            "appointment-details-panel.close_history"
          ],
          "stateReads": [
            "control-room-rail.activeToolId",
            "appointment-details-panel.eventId",
            "appointment-details-panel.loadStatus"
          ],
          "apiActions": [
            "appointment.read"
          ]
        },
        {
          "name": "create_appointment",
          "safety": "phi",
          "description": "Book a new appointment in the editor panel, docked from the New appointment button, from a click on an empty slot (prefilled with the slot, the clicked column and the cog's default duration) or from an online booking being processed. A host without the tool rail shows the same form in AppointmentEditorDialog, a modal with no rail to open. Set the patient, the linked care or care-plan lines, the date, start time and duration, the operator, chair, branch and colour, the description (255 characters at most — a longer one blocks the save), and, once a patient is chosen, the SMS and e-mail reminders, the first-visit question and — where the patient has unsigned required documents — how they are asked to sign. Repeats sets a frequency and, where the host allows it, a Custom rule (every N days, weeks, months or years; chosen weekdays, always including the first appointment's; or the day or nth weekday of the month) ending after a number of times or on a date. Busy chair, busy operator and operator-away warnings are advisory and do not hold the save; only a practice closure does. Enter submits from any text field. Writes patient-identifiable data.",
          "descriptionKey": "ui.agent.calendar.workflows.createAppointment",
          "uiActions": [
            "combobox.set_value",
            "combobox.apply_filter",
            "select.set_value",
            "date-picker.set_date",
            "time-picker.set_time",
            "color-picker.set_value",
            "text-input.set_value",
            "text-area.set_value",
            "number-input.set_value",
            "checkbox.set_checked",
            "radio-group.set_value",
            "control-room-rail.open"
          ],
          "stateReads": [
            "combobox.value",
            "select.value",
            "date-picker.value",
            "time-picker.value",
            "checkbox.checked",
            "radio-group.value",
            "control-room-rail.activeToolId"
          ],
          "apiActions": [
            "patient.search",
            "appointment.create"
          ]
        },
        {
          "name": "edit_appointment",
          "safety": "phi",
          "description": "Amend an existing appointment in the docked editor. With the host's details read the editor opens from Edit on the details panel and Cancel or Save returns there; without it the details panel is the form. A remote host first loads canonical data; loading, failure and whole-appointment refusal expose no editable form. When that data carries a series, the editor first asks the scope: this occurrence, this and following, or the whole series. Honour the returned patient, care, description and recurrence capabilities. A refused recurring scope cannot be treated as an ordinary edit. Save waits for host acceptance before closing or announcing success; rejection preserves the entered draft for correction or retry. Writes patient-identifiable data.",
          "descriptionKey": "ui.agent.calendar.workflows.editAppointment",
          "uiActions": [
            "calendar.focus_event",
            "combobox.set_value",
            "select.set_value",
            "date-picker.set_date",
            "time-picker.set_time",
            "color-picker.set_value",
            "text-input.set_value",
            "text-area.set_value",
            "radio-group.set_value"
          ],
          "stateReads": [
            "combobox.value",
            "select.value",
            "date-picker.value",
            "time-picker.value",
            "radio-group.value",
            "calendar.currentDate"
          ],
          "apiActions": [
            "appointment.read",
            "patient.search",
            "appointment.update",
            "appointmentSeries.applyScope"
          ]
        },
        {
          "name": "change_appointment_status",
          "safety": "phi",
          "description": "Set an appointment's attendance status from the status control in the details panel (appointment-details-panel). The workspace offers all six statuses; allowedStatuses lists what set_status accepts. A refusal keeps the previous status and shows the host's message. The status is patient-identifiable attendance data.",
          "descriptionKey": "ui.agent.calendar.workflows.changeAppointmentStatus",
          "uiActions": [
            "calendar.focus_event",
            "appointment-details-panel.set_status"
          ],
          "stateReads": [
            "appointment-details-panel.appointmentStatus",
            "appointment-details-panel.allowedStatuses"
          ],
          "apiActions": [
            "appointment.setStatus"
          ]
        },
        {
          "name": "move_appointment",
          "safety": "phi",
          "description": "Reschedule an appointment either by dragging its card to a new slot or by arming \"Move…\" in the details panel and then clicking the target slot — the panel stays docked and a banner tinted with the appointment's own colour names what is being placed. Either route ends in the confirmation dialog, which offers the SMS and e-mail notify channels and, for a series member, the recurring scope. A host recurring parent always confirms, asks the scope and hides the notify channels, as the platform does. Cancelling reverts the card and commits nothing. Writes patient-identifiable data.",
          "descriptionKey": "ui.agent.calendar.workflows.moveAppointment",
          "uiActions": [
            "calendar.focus_event",
            "calendar.goto_date",
            "dialog.open",
            "dialog.close",
            "dialog.dismiss",
            "checkbox.set_checked",
            "radio-group.set_value"
          ],
          "stateReads": [
            "dialog.isOpen",
            "checkbox.checked",
            "radio-group.value",
            "calendar.currentDate"
          ],
          "apiActions": [
            "appointment.reschedule",
            "patient.notifyAppointmentChange"
          ]
        },
        {
          "name": "resize_appointment",
          "safety": "phi",
          "description": "Change an appointment's duration by dragging its card edge. Unlike a move this SAVES AT ONCE with no confirmation, exactly as the platform does; the toast that follows carries an Undo that restores the previous duration and logs both changes on the appointment's history. Writes patient-identifiable data.",
          "descriptionKey": "ui.agent.calendar.workflows.resizeAppointment",
          "uiActions": [
            "calendar.focus_event",
            "toast.dismiss"
          ],
          "stateReads": [
            "toast.visibleToasts"
          ],
          "apiActions": [
            "appointment.update"
          ]
        },
        {
          "name": "copy_appointment",
          "safety": "phi",
          "description": "Duplicate an appointment onto another slot: arm \"Copy…\" in the details panel, then click the target. The copy lands immediately with no confirmation, and its toast carries an Undo. A plan-linked appointment first asks whether to copy the appointment only or the appointment and its treatments. Writes patient-identifiable data.",
          "descriptionKey": "ui.agent.calendar.workflows.copyAppointment",
          "uiActions": [
            "calendar.focus_event",
            "calendar.goto_date",
            "toast.dismiss",
            "radio-group.set_value"
          ],
          "stateReads": [
            "calendar.currentDate",
            "toast.visibleToasts",
            "radio-group.value"
          ],
          "apiActions": [
            "appointment.duplicate"
          ]
        },
        {
          "name": "delete_appointment",
          "safety": "destructive",
          "description": "Remove an appointment from the details panel behind an alert dialog. The dialog asks for the recurring scope when the appointment belongs to a series, and for the care-plan cleanup when it is the parent of a price-list recurrence — so confirming can drop far more than the one card. Irreversible from this surface.",
          "descriptionKey": "ui.agent.calendar.workflows.deleteAppointment",
          "uiActions": [
            "calendar.focus_event",
            "dialog.open",
            "dialog.close",
            "dialog.dismiss",
            "radio-group.set_value"
          ],
          "stateReads": [
            "dialog.isOpen",
            "radio-group.value"
          ],
          "apiActions": [
            "appointment.delete",
            "appointmentSeries.applyScope"
          ]
        },
        {
          "name": "manage_patient_notes",
          "safety": "phi",
          "description": "Read and write the patient's notes from the conditional Notes rail tool: add a note through the composer, edit one in place, pin or flag one, or delete one behind the panel's alert dialog. Every write goes to the host on the click, and the host stamps the note's id, time and author. The kit attributes nothing to a clinical note. A refused delete, pin or flag is rolled back and explained in the panel. An HTML note edits in a rich text editor and saves as HTML; a clinical or deleted note offers no edit. With no host seam, or when the host's seam is not writable, the tool is a read-only timeline. Explicit note permissions take precedence over appointment-edit permission. Details and the editor have no Notes sub-view. The rows carry ids and pin / flag / clinical markers only; the body and author are never exposed as state. Writes patient-identifiable clinical data.",
          "descriptionKey": "ui.agent.calendar.workflows.managePatientNotes",
          "uiActions": [
            "notes-panel.add_note",
            "notes-panel.toggle_pin",
            "notes-panel.toggle_flag",
            "dialog.open",
            "dialog.close",
            "dialog.dismiss",
            "text-area.set_value",
            "rich-text-editor.set_content"
          ],
          "stateReads": [
            "notes-panel.notes",
            "notes-panel.canAddClinical",
            "notes-panel.currentNoteId",
            "dialog.isOpen"
          ],
          "apiActions": [
            "patientNote.create",
            "patientNote.update",
            "patientNote.delete",
            "patientNote.pin",
            "patientNote.flag"
          ]
        },
        {
          "name": "manage_task",
          "safety": "phi",
          "description": "Create, edit, complete or delete a practice task in the editor tool's slot, in the published task editor. The toolbar's New task member opens an empty task, dated from the grid's selection or now; a click on a task row on the grid opens that task, read through the host. Set the date, the note, the type, the assignee and at most one counterpart (a patient, a company or an operator), then save through the host. Done and Delete act on a saved task at once. Each action is withheld when the host passes no seam for it. A task can link a patient, so writes are patient-identifiable.",
          "descriptionKey": "ui.agent.calendar.workflows.manageTask",
          "uiActions": [
            "task-editor.set_fields",
            "task-editor.save",
            "task-editor.set_done",
            "task-editor.delete",
            "task-editor.cancel"
          ],
          "stateReads": [
            "control-room-rail.activeToolId",
            "task-editor.status",
            "task-editor.draft",
            "task-editor.canSave"
          ],
          "apiActions": [
            "task.read",
            "task.create",
            "task.update",
            "task.setDone",
            "task.delete"
          ]
        },
        {
          "name": "read_modification_history",
          "safety": "read",
          "description": "Open the History sub-view of the details panel and read the appointment's modification ledger, newest first — what changed, from what to what, and when. No mutation.",
          "descriptionKey": "ui.agent.calendar.workflows.readModificationHistory",
          "uiActions": [
            "calendar.focus_event",
            "appointment-details-panel.open_history",
            "appointment-details-panel.close_history"
          ],
          "stateReads": [
            "appointment-details-panel.eventId",
            "appointment-details-panel.loadStatus",
            "appointment-details-panel.historyOpen"
          ],
          "apiActions": [
            "appointment.listHistory"
          ]
        },
        {
          "name": "request_signature",
          "safety": "phi",
          "description": "Ask the patient to sign the appointment's documents from the details panel, by SMS or e-mail through the kit menu. The chip beside it reports the channel a request has already gone out on. There is no \"On this device…\" item: on-device signing is the host's own e-signature surface and no seam here mounts it, so the menu offers only the two channels it can honour. Sends a patient-identifiable request.",
          "descriptionKey": "ui.agent.calendar.workflows.requestSignature",
          "uiActions": [
            "dropdown-menu.open",
            "dropdown-menu.close"
          ],
          "stateReads": [
            "dropdown-menu.isOpen"
          ],
          "apiActions": [
            "signature.request"
          ]
        },
        {
          "name": "create_document",
          "safety": "phi",
          "description": "Open the appointment details create menu through data-action=\"open-create-document\" and select an offered data-action=\"create-document-<kind>\" item: bill, folder, template, empty, identification or webcam. The host supplies permitted kinds and owns navigation, confirmation and persistence. Appointment read-only mode does not withhold document rights. A selection starts the host workflow; it does not prove that a document or bill was created. May write patient-identifiable data.",
          "descriptionKey": "ui.agent.calendar.workflows.createDocument",
          "uiActions": [
            "dropdown-menu.open",
            "dropdown-menu.close"
          ],
          "stateReads": [
            "dropdown-menu.isOpen"
          ],
          "apiActions": []
        },
        {
          "name": "message_patient_whatsapp",
          "safety": "phi",
          "description": "Reach the patient over WhatsApp from a waiting-list row. The affordance is a `wa.me` deep link the row opens in a new tab — it is disabled, and names its reason in its accessible name, when the entry carries no WhatsApp-capable number. There is no equivalent in the details panel: the send-reminder group is handed an empty channel list, because the host's legacy Snippets island is the only composing surface and no seam here mounts it. Hands a patient's contact detail to an outbound channel.",
          "descriptionKey": "ui.agent.calendar.workflows.messagePatientWhatsapp",
          "uiActions": [],
          "apiActions": []
        },
        {
          "name": "filter_waiting_list",
          "safety": "read",
          "description": "Narrow the waiting queue: the four quick views (all, patients without an appointment, appointment scheduled over 30 days ago, on the list over 30 days) and, behind \"Show advanced filters\", the platform's nine optional client-side inputs — patient, patient assigned, operator, appointment scheduled, appointment scheduled from / to, on the waiting list from / to and description — applied only when \"Filter list\" is pressed. The toggle carries a count badge while any input is set, and changing the quick view drops the form. Selection only.",
          "descriptionKey": "ui.agent.calendar.workflows.filterWaitingList",
          "uiActions": [
            "select.set_value",
            "combobox.set_value",
            "date-picker.set_date",
            "text-area.set_value"
          ],
          "stateReads": [
            "select.value",
            "combobox.value",
            "date-picker.value",
            "text-area.value"
          ],
          "apiActions": []
        },
        {
          "name": "manage_waiting_list_entry",
          "safety": "phi",
          "description": "Add, amend or remove a waiting-list entry. The four-field form opens as a rail SUB-VIEW — from the toolbar split button's plus segment, from Add entry, or from a row's pencil — with a back arrow to the queue. Editing is refused on a row already linked to an appointment, because those fields belong to the appointment; the pencil stays focusable and names that reason. Remove deletes at once with no confirmation, platform parity, and its toast carries an Undo that puts the entry back. Writes patient-identifiable data.",
          "descriptionKey": "ui.agent.calendar.workflows.manageWaitingListEntry",
          "uiActions": [
            "combobox.set_value",
            "select.set_value",
            "color-picker.set_value",
            "text-area.set_value",
            "toast.dismiss"
          ],
          "stateReads": [
            "combobox.value",
            "select.value",
            "text-area.value",
            "toast.visibleToasts"
          ],
          "apiActions": [
            "waitingListEntry.create",
            "waitingListEntry.update",
            "waitingListEntry.delete"
          ]
        },
        {
          "name": "schedule_waiting_patient",
          "safety": "phi",
          "description": "Give a waiting patient a slot. \"Schedule\" on an unlinked row hands off to the free-slot finder seeded from the entry — operator, chair, duration, patient, care and colour already filled in — and booking a slot opens the editor carrying the entry, so saving books the appointment and takes the entry off the list. A row already linked to an appointment reads \"Reschedule\" and seeds the same finder, but booking there MOVES the existing appointment rather than creating a second one. Writes patient-identifiable data.",
          "descriptionKey": "ui.agent.calendar.workflows.scheduleWaitingPatient",
          "uiActions": [
            "control-room-rail.open",
            "calendar.goto_date",
            "date-picker.set_date",
            "time-picker.set_time"
          ],
          "stateReads": [
            "control-room-rail.activeToolId",
            "calendar.currentDate"
          ],
          "apiActions": [
            "waitingListEntry.schedule",
            "appointment.create",
            "appointment.reschedule"
          ]
        },
        {
          "name": "find_free_slot",
          "safety": "read",
          "description": "Search the practice for bookable time in the finder panel. Operator and chair scope are grouped checklists behind a popover per axis — a select-all row first, operators sectioned under their groups, nothing ticked searching every eligible resource — beside the care, the duration, the date range and, for a care that needs one, a medical-device select. The results list groups the slots under a day heading; when the viewer may write appointments, a click steers the grid to that day and docks the editor prefilled with the date, time, duration, chair, operator and any seeded patient or care; read-only viewers see the list and projection only, under a lock note, with no Book. The 185-day range warning is advisory (the search still runs), \"Show more slots\" pushes the To date out by 30 days and re-searches, and an alert names which business hours are missing when the practice or its operators hold none (it links to the scheduler only where the host supplies that navigation, which this workspace does not). Projected bands open a modal list of original options by click, Enter or Space; only an explicit Book action uses the finder booking path. Read-only viewers can scroll those options without Book. Dismissal restores focus to the band.",
          "descriptionKey": "ui.agent.calendar.workflows.findFreeSlot",
          "uiActions": [
            "collapsible.toggle",
            "popover.open",
            "popover.close",
            "checkbox.set_checked",
            "combobox.set_value",
            "select.set_value",
            "date-picker.set_date",
            "switch.set_checked"
          ],
          "stateReads": [
            "collapsible.isOpen",
            "popover.isOpen",
            "checkbox.checked",
            "combobox.value",
            "select.value",
            "date-picker.value",
            "switch.checked"
          ],
          "apiActions": [
            "availability.search"
          ]
        },
        {
          "name": "triage_online_booking",
          "safety": "phi",
          "description": "Review the online-bookings queue independently of the visible dates. The host owns membership and loading/error state. Show a row on the grid; completion is available only when the host enables it and the user can edit. Review-only rows remain in the queue on selection and cannot be dragged, resized or edited. Unknown last-seen data never marks a booking New. A host addresses one booking with the focusBookingId prop (bump focusBookingKey to repeat it): the tool docks, then the card carrying that data-booking-id takes focus and aria-current; an id outside the queue addresses nothing. An Assign patient or Assign operator segment opens the editor focused on that field. A settings cog in the panel header (data-backlog-settings) opens a menu (instance id calendar-backlog-settings) of three switch rows — withoutPatient, withoutOperator, withoutChair, the chair one only where the practice has chairs — all on by default, then a Reset row that switches them all back on; set_checked with the name of a row flips it; a card stays listed while at least one of its own gaps is still switched on. Read the cog before reading the list: while any switch is off it carries data-narrowed and its accessible name says the list is filtered, so a short queue is not an empty backlog. Selection only; completing writes patient-identifiable data.",
          "descriptionKey": "ui.agent.calendar.workflows.triageOnlineBooking",
          "uiActions": [
            "calendar.focus_event",
            "control-room-rail.open",
            "dropdown-menu.open",
            "dropdown-menu.close",
            "dropdown-menu.set_checked"
          ],
          "stateReads": [
            "control-room-rail.activeToolId",
            "dropdown-menu.isOpen"
          ],
          "apiActions": [
            "onlineBooking.list",
            "onlineBooking.process"
          ]
        },
        {
          "name": "print_day_sheet",
          "safety": "phi",
          "description": "Print the front-desk call sheet. The toolbar's printer icon opens a dialog asking which day — one day, never the visible range — and Print renders that day's appointments through the browser, scoped by the filters in force and masked when privacy mode is on. Nothing is sent to a server, but the sheet itself is a patient-identifiable document.",
          "descriptionKey": "ui.agent.calendar.workflows.printDaySheet",
          "uiActions": [
            "dialog.open",
            "dialog.close",
            "dialog.dismiss",
            "date-picker.set_date"
          ],
          "stateReads": [
            "dialog.isOpen",
            "date-picker.value"
          ],
          "apiActions": []
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "care-plan-editor",
      "composes": [
        {
          "component": "care-plan-header",
          "as": "planHeader"
        },
        {
          "component": "tooth-scheme",
          "as": "odontogram",
          "entity": "tooth"
        },
        {
          "component": "data-table",
          "as": "treatmentsGrid",
          "entity": "treatment"
        },
        {
          "component": "radiograph-panel",
          "as": "radiographs",
          "entity": "radiograph"
        },
        {
          "component": "control-room-rail",
          "as": "toolRail"
        },
        {
          "component": "notes-panel",
          "as": "planNotes",
          "entity": "note"
        },
        {
          "component": "tasks-panel",
          "as": "planTasks",
          "entity": "task"
        },
        {
          "component": "entity-summary",
          "as": "planSummary"
        }
      ],
      "workflows": [
        {
          "name": "select_plan",
          "safety": "read",
          "description": "Open one of the patient's care plans from the plan list. Activation is a native click on the plan row; the host loads the plan into the editor.",
          "descriptionKey": "ui.agent.carePlanEditor.workflows.selectPlan",
          "uiActions": [],
          "apiActions": [
            "carePlan.get"
          ]
        },
        {
          "name": "add_plan",
          "safety": "write",
          "description": "Create a new care plan for the patient.",
          "descriptionKey": "ui.agent.carePlanEditor.workflows.addPlan",
          "uiActions": [],
          "apiActions": [
            "carePlan.create"
          ]
        },
        {
          "name": "inspect_tooth",
          "safety": "read",
          "description": "Focus a tooth on the odontogram and read its charted dental status.",
          "descriptionKey": "ui.agent.carePlanEditor.workflows.inspectTooth",
          "uiActions": [
            "tooth-scheme.focus_tooth"
          ],
          "stateReads": [
            "tooth-scheme.chart"
          ],
          "apiActions": []
        },
        {
          "name": "open_tooth_radiographs",
          "safety": "read",
          "description": "Open the radiograph drawer for a tooth that carries imaging (the docked Control Room radiographs tool).",
          "descriptionKey": "ui.agent.carePlanEditor.workflows.openToothRadiographs",
          "uiActions": [
            "tooth-scheme.open_radiographs",
            "control-room-rail.select_tool"
          ],
          "stateReads": [
            "tooth-scheme.teethWithRadiographs"
          ],
          "apiActions": []
        },
        {
          "name": "mark_treatment_done",
          "safety": "write",
          "description": "Mark a planned treatment as executed from its row action in the treatments grid.",
          "descriptionKey": "ui.agent.carePlanEditor.workflows.markTreatmentDone",
          "uiActions": [],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": [
            "carePlanTreatment.update"
          ]
        },
        {
          "name": "add_treatment",
          "safety": "write",
          "description": "Add a planned treatment row to the current plan.",
          "descriptionKey": "ui.agent.carePlanEditor.workflows.addTreatment",
          "uiActions": [],
          "apiActions": [
            "carePlanTreatment.create"
          ]
        },
        {
          "name": "remove_treatment",
          "safety": "destructive",
          "description": "Remove the selected planned treatment(s) from the plan (read data-table.selection for the targets).",
          "descriptionKey": "ui.agent.carePlanEditor.workflows.removeTreatment",
          "uiActions": [],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": [
            "carePlanTreatment.delete"
          ]
        },
        {
          "name": "save_plan",
          "safety": "write",
          "description": "Persist the current edits to the care plan.",
          "descriptionKey": "ui.agent.carePlanEditor.workflows.savePlan",
          "uiActions": [],
          "apiActions": [
            "carePlan.update"
          ]
        },
        {
          "name": "add_plan_note",
          "safety": "phi",
          "description": "Add a note to the plan via the docked Notes tool. A clinical note requires the clinical-note permission.",
          "descriptionKey": "ui.agent.carePlanEditor.workflows.addPlanNote",
          "uiActions": [
            "notes-panel.add_note"
          ],
          "apiActions": [
            "note.create"
          ]
        },
        {
          "name": "triage_plan_tasks",
          "safety": "write",
          "description": "Open or complete a follow-up task from the docked Tasks tool.",
          "descriptionKey": "ui.agent.carePlanEditor.workflows.triagePlanTasks",
          "uiActions": [
            "tasks-panel.select_item",
            "tasks-panel.toggle_done"
          ],
          "stateReads": [
            "tasks-panel.items"
          ],
          "apiActions": [
            "task.update"
          ]
        },
        {
          "name": "regenerate_summary",
          "safety": "write",
          "description": "Regenerate the AI plan summary in the docked AI summary tool.",
          "descriptionKey": "ui.agent.carePlanEditor.workflows.regenerateSummary",
          "uiActions": [
            "entity-summary.regenerate"
          ],
          "apiActions": [
            "alia.summarise"
          ]
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "care-plan-editor-aesthetic",
      "composes": [
        {
          "component": "care-plan-header",
          "as": "planHeader"
        },
        {
          "component": "muscle-scheme",
          "as": "bodyMap",
          "entity": "region"
        },
        {
          "component": "face-scheme",
          "as": "faceMap",
          "entity": "zone"
        },
        {
          "component": "data-table",
          "as": "treatmentsGrid",
          "entity": "treatment"
        },
        {
          "component": "control-room-rail",
          "as": "toolRail"
        },
        {
          "component": "entity-summary",
          "as": "planSummary"
        }
      ],
      "workflows": [
        {
          "name": "select_plan",
          "safety": "read",
          "description": "Open one of the patient's aesthetic-medicine care plans from the plan list.",
          "descriptionKey": "ui.agent.aestheticCarePlanEditor.workflows.selectPlan",
          "uiActions": [],
          "apiActions": [
            "carePlan.get"
          ]
        },
        {
          "name": "add_plan",
          "safety": "write",
          "description": "Create a new aesthetic-medicine care plan for the patient.",
          "descriptionKey": "ui.agent.aestheticCarePlanEditor.workflows.addPlan",
          "uiActions": [],
          "apiActions": [
            "carePlan.create"
          ]
        },
        {
          "name": "inspect_area",
          "safety": "read",
          "description": "Focus a body or face region on the anatomy anchor and read its charted treatment areas.",
          "descriptionKey": "ui.agent.aestheticCarePlanEditor.workflows.inspectArea",
          "uiActions": [
            "muscle-scheme.focus_region",
            "face-scheme.focus_zone"
          ],
          "stateReads": [
            "muscle-scheme.chart",
            "face-scheme.chart"
          ],
          "apiActions": []
        },
        {
          "name": "mark_treatment_done",
          "safety": "write",
          "description": "Mark a planned treatment as executed from its row action in the treatments grid.",
          "descriptionKey": "ui.agent.aestheticCarePlanEditor.workflows.markTreatmentDone",
          "uiActions": [],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": [
            "carePlanTreatment.update"
          ]
        },
        {
          "name": "add_treatment",
          "safety": "write",
          "description": "Add a planned treatment row to the current care plan.",
          "descriptionKey": "ui.agent.aestheticCarePlanEditor.workflows.addTreatment",
          "uiActions": [],
          "apiActions": [
            "carePlanTreatment.create"
          ]
        },
        {
          "name": "remove_treatment",
          "safety": "destructive",
          "description": "Remove the selected treatment(s) from the plan (read data-table.selection for the targets).",
          "descriptionKey": "ui.agent.aestheticCarePlanEditor.workflows.removeTreatment",
          "uiActions": [],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": [
            "carePlanTreatment.delete"
          ]
        },
        {
          "name": "save_plan",
          "safety": "write",
          "description": "Persist the current edits to the aesthetic-medicine care plan.",
          "descriptionKey": "ui.agent.aestheticCarePlanEditor.workflows.savePlan",
          "uiActions": [],
          "apiActions": [
            "carePlan.update"
          ]
        },
        {
          "name": "regenerate_summary",
          "safety": "write",
          "description": "Regenerate the AI plan summary in the docked Plan summary tool.",
          "descriptionKey": "ui.agent.aestheticCarePlanEditor.workflows.regenerateSummary",
          "uiActions": [
            "entity-summary.regenerate"
          ],
          "apiActions": [
            "alia.summarise"
          ]
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "care-plan-editor-dermatology",
      "composes": [
        {
          "component": "care-plan-header",
          "as": "planHeader"
        },
        {
          "component": "muscle-scheme",
          "as": "bodyMap",
          "entity": "region"
        },
        {
          "component": "face-scheme",
          "as": "faceMap",
          "entity": "zone"
        },
        {
          "component": "data-table",
          "as": "treatmentsGrid",
          "entity": "treatment"
        },
        {
          "component": "control-room-rail",
          "as": "toolRail"
        },
        {
          "component": "entity-summary",
          "as": "planSummary"
        }
      ],
      "workflows": [
        {
          "name": "select_plan",
          "safety": "read",
          "description": "Open one of the patient's dermatology / skin-lesion care plans from the plan list.",
          "descriptionKey": "ui.agent.dermatologyCarePlanEditor.workflows.selectPlan",
          "uiActions": [],
          "apiActions": [
            "carePlan.get"
          ]
        },
        {
          "name": "add_plan",
          "safety": "write",
          "description": "Create a new dermatology / skin-lesion care plan for the patient.",
          "descriptionKey": "ui.agent.dermatologyCarePlanEditor.workflows.addPlan",
          "uiActions": [],
          "apiActions": [
            "carePlan.create"
          ]
        },
        {
          "name": "inspect_lesion",
          "safety": "read",
          "description": "Focus a body or face region on the skin-lesion anchor and read its charted lesions.",
          "descriptionKey": "ui.agent.dermatologyCarePlanEditor.workflows.inspectLesion",
          "uiActions": [
            "muscle-scheme.focus_region",
            "face-scheme.focus_zone"
          ],
          "stateReads": [
            "muscle-scheme.chart",
            "face-scheme.chart"
          ],
          "apiActions": []
        },
        {
          "name": "mark_treatment_done",
          "safety": "write",
          "description": "Mark a planned procedure as executed from its row action in the treatments grid.",
          "descriptionKey": "ui.agent.dermatologyCarePlanEditor.workflows.markTreatmentDone",
          "uiActions": [],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": [
            "carePlanTreatment.update"
          ]
        },
        {
          "name": "add_treatment",
          "safety": "write",
          "description": "Add a planned procedure row to the current care plan.",
          "descriptionKey": "ui.agent.dermatologyCarePlanEditor.workflows.addTreatment",
          "uiActions": [],
          "apiActions": [
            "carePlanTreatment.create"
          ]
        },
        {
          "name": "remove_treatment",
          "safety": "destructive",
          "description": "Remove the selected procedure(s) from the plan (read data-table.selection for the targets).",
          "descriptionKey": "ui.agent.dermatologyCarePlanEditor.workflows.removeTreatment",
          "uiActions": [],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": [
            "carePlanTreatment.delete"
          ]
        },
        {
          "name": "save_plan",
          "safety": "write",
          "description": "Persist the current edits to the dermatology / skin-lesion care plan.",
          "descriptionKey": "ui.agent.dermatologyCarePlanEditor.workflows.savePlan",
          "uiActions": [],
          "apiActions": [
            "carePlan.update"
          ]
        },
        {
          "name": "regenerate_summary",
          "safety": "write",
          "description": "Regenerate the AI plan summary in the docked Plan summary tool.",
          "descriptionKey": "ui.agent.dermatologyCarePlanEditor.workflows.regenerateSummary",
          "uiActions": [
            "entity-summary.regenerate"
          ],
          "apiActions": [
            "alia.summarise"
          ]
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "care-plan-editor-dietitian",
      "composes": [
        {
          "component": "care-plan-header",
          "as": "planHeader"
        },
        {
          "component": "data-table",
          "as": "servicesGrid",
          "entity": "treatment"
        },
        {
          "component": "control-room-rail",
          "as": "toolRail"
        },
        {
          "component": "entity-summary",
          "as": "planSummary"
        }
      ],
      "workflows": [
        {
          "name": "select_plan",
          "safety": "read",
          "description": "Open one of the patient's nutrition / weight-management care plans from the plan list.",
          "descriptionKey": "ui.agent.dietitianCarePlanEditor.workflows.selectPlan",
          "uiActions": [],
          "apiActions": [
            "carePlan.get"
          ]
        },
        {
          "name": "add_plan",
          "safety": "write",
          "description": "Create a new nutrition care plan for the patient.",
          "descriptionKey": "ui.agent.dietitianCarePlanEditor.workflows.addPlan",
          "uiActions": [],
          "apiActions": [
            "carePlan.create"
          ]
        },
        {
          "name": "mark_service_done",
          "safety": "write",
          "description": "Mark a planned service as delivered from its row action in the services grid.",
          "descriptionKey": "ui.agent.dietitianCarePlanEditor.workflows.markServiceDone",
          "uiActions": [],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": [
            "carePlanTreatment.update"
          ]
        },
        {
          "name": "add_service",
          "safety": "write",
          "description": "Add a service row (consultation, meal plan, supplement, …) to the plan.",
          "descriptionKey": "ui.agent.dietitianCarePlanEditor.workflows.addService",
          "uiActions": [],
          "apiActions": [
            "carePlanTreatment.create"
          ]
        },
        {
          "name": "remove_service",
          "safety": "destructive",
          "description": "Remove the selected service(s) from the plan (read data-table.selection for the targets).",
          "descriptionKey": "ui.agent.dietitianCarePlanEditor.workflows.removeService",
          "uiActions": [],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": [
            "carePlanTreatment.delete"
          ]
        },
        {
          "name": "save_plan",
          "safety": "write",
          "description": "Persist the current edits to the nutrition care plan.",
          "descriptionKey": "ui.agent.dietitianCarePlanEditor.workflows.savePlan",
          "uiActions": [],
          "apiActions": [
            "carePlan.update"
          ]
        },
        {
          "name": "regenerate_summary",
          "safety": "write",
          "description": "Regenerate the AI plan summary in the docked Plan summary tool.",
          "descriptionKey": "ui.agent.dietitianCarePlanEditor.workflows.regenerateSummary",
          "uiActions": [
            "entity-summary.regenerate"
          ],
          "apiActions": [
            "alia.summarise"
          ]
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "care-plan-editor-ophthalmology",
      "composes": [
        {
          "component": "care-plan-header",
          "as": "planHeader"
        },
        {
          "component": "optical-prescription",
          "as": "prescription",
          "entity": "eye"
        },
        {
          "component": "data-table",
          "as": "productsGrid",
          "entity": "treatment"
        },
        {
          "component": "control-room-rail",
          "as": "toolRail"
        },
        {
          "component": "entity-summary",
          "as": "planSummary"
        }
      ],
      "workflows": [
        {
          "name": "select_plan",
          "safety": "read",
          "description": "Open one of the patient's optical / glasses care plans from the plan list.",
          "descriptionKey": "ui.agent.ophthalmologyCarePlanEditor.workflows.selectPlan",
          "uiActions": [],
          "apiActions": [
            "carePlan.get"
          ]
        },
        {
          "name": "add_plan",
          "safety": "write",
          "description": "Create a new optical / glasses care plan for the patient.",
          "descriptionKey": "ui.agent.ophthalmologyCarePlanEditor.workflows.addPlan",
          "uiActions": [],
          "apiActions": [
            "carePlan.create"
          ]
        },
        {
          "name": "inspect_prescription",
          "safety": "read",
          "description": "Focus an eye's row on the glasses-prescription anchor and read its refraction (sphere / cylinder / axis / add) per distance band.",
          "descriptionKey": "ui.agent.ophthalmologyCarePlanEditor.workflows.inspectPrescription",
          "uiActions": [
            "optical-prescription.focus_eye",
            "optical-prescription.get_row"
          ],
          "stateReads": [
            "optical-prescription.prescription",
            "optical-prescription.bands"
          ],
          "apiActions": []
        },
        {
          "name": "mark_product_done",
          "safety": "write",
          "description": "Mark a planned product as dispensed from its row action in the products grid.",
          "descriptionKey": "ui.agent.ophthalmologyCarePlanEditor.workflows.markProductDone",
          "uiActions": [],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": [
            "carePlanTreatment.update"
          ]
        },
        {
          "name": "add_product",
          "safety": "write",
          "description": "Add a product row (lens, frame, coating, …) to the plan.",
          "descriptionKey": "ui.agent.ophthalmologyCarePlanEditor.workflows.addProduct",
          "uiActions": [],
          "apiActions": [
            "carePlanTreatment.create"
          ]
        },
        {
          "name": "remove_product",
          "safety": "destructive",
          "description": "Remove the selected product(s) from the plan (read data-table.selection for the targets).",
          "descriptionKey": "ui.agent.ophthalmologyCarePlanEditor.workflows.removeProduct",
          "uiActions": [],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": [
            "carePlanTreatment.delete"
          ]
        },
        {
          "name": "save_plan",
          "safety": "write",
          "description": "Persist the current edits to the optical care plan.",
          "descriptionKey": "ui.agent.ophthalmologyCarePlanEditor.workflows.savePlan",
          "uiActions": [],
          "apiActions": [
            "carePlan.update"
          ]
        },
        {
          "name": "regenerate_summary",
          "safety": "write",
          "description": "Regenerate the AI plan summary in the docked Plan summary tool.",
          "descriptionKey": "ui.agent.ophthalmologyCarePlanEditor.workflows.regenerateSummary",
          "uiActions": [
            "entity-summary.regenerate"
          ],
          "apiActions": [
            "alia.summarise"
          ]
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "care-plan-editor-orthopedics",
      "composes": [
        {
          "component": "care-plan-header",
          "as": "planHeader"
        },
        {
          "component": "muscle-scheme",
          "as": "bodyMap",
          "entity": "region"
        },
        {
          "component": "data-table",
          "as": "treatmentsGrid",
          "entity": "treatment"
        },
        {
          "component": "control-room-rail",
          "as": "toolRail"
        },
        {
          "component": "entity-summary",
          "as": "planSummary"
        }
      ],
      "workflows": [
        {
          "name": "select_plan",
          "safety": "read",
          "description": "Open one of the patient's orthopaedic / musculoskeletal care plans from the plan list.",
          "descriptionKey": "ui.agent.orthopedicsCarePlanEditor.workflows.selectPlan",
          "uiActions": [],
          "apiActions": [
            "carePlan.get"
          ]
        },
        {
          "name": "add_plan",
          "safety": "write",
          "description": "Create a new orthopaedic / musculoskeletal care plan for the patient.",
          "descriptionKey": "ui.agent.orthopedicsCarePlanEditor.workflows.addPlan",
          "uiActions": [],
          "apiActions": [
            "carePlan.create"
          ]
        },
        {
          "name": "inspect_injury",
          "safety": "read",
          "description": "Focus a body region on the fracture / joint anchor and read its charted injury sites.",
          "descriptionKey": "ui.agent.orthopedicsCarePlanEditor.workflows.inspectInjury",
          "uiActions": [
            "muscle-scheme.focus_region"
          ],
          "stateReads": [
            "muscle-scheme.chart"
          ],
          "apiActions": []
        },
        {
          "name": "mark_treatment_done",
          "safety": "write",
          "description": "Mark a planned procedure as executed from its row action in the treatments grid.",
          "descriptionKey": "ui.agent.orthopedicsCarePlanEditor.workflows.markTreatmentDone",
          "uiActions": [],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": [
            "carePlanTreatment.update"
          ]
        },
        {
          "name": "add_treatment",
          "safety": "write",
          "description": "Add a planned procedure row to the current care plan.",
          "descriptionKey": "ui.agent.orthopedicsCarePlanEditor.workflows.addTreatment",
          "uiActions": [],
          "apiActions": [
            "carePlanTreatment.create"
          ]
        },
        {
          "name": "remove_treatment",
          "safety": "destructive",
          "description": "Remove the selected procedure(s) from the plan (read data-table.selection for the targets).",
          "descriptionKey": "ui.agent.orthopedicsCarePlanEditor.workflows.removeTreatment",
          "uiActions": [],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": [
            "carePlanTreatment.delete"
          ]
        },
        {
          "name": "save_plan",
          "safety": "write",
          "description": "Persist the current edits to the orthopaedic / musculoskeletal care plan.",
          "descriptionKey": "ui.agent.orthopedicsCarePlanEditor.workflows.savePlan",
          "uiActions": [],
          "apiActions": [
            "carePlan.update"
          ]
        },
        {
          "name": "regenerate_summary",
          "safety": "write",
          "description": "Regenerate the AI plan summary in the docked Plan summary tool.",
          "descriptionKey": "ui.agent.orthopedicsCarePlanEditor.workflows.regenerateSummary",
          "uiActions": [
            "entity-summary.regenerate"
          ],
          "apiActions": [
            "alia.summarise"
          ]
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "care-plan-editor-physio",
      "composes": [
        {
          "component": "care-plan-header",
          "as": "planHeader"
        },
        {
          "component": "data-table",
          "as": "treatmentsGrid",
          "entity": "treatment"
        },
        {
          "component": "control-room-rail",
          "as": "toolRail"
        },
        {
          "component": "notes-panel",
          "as": "planNotes",
          "entity": "note"
        },
        {
          "component": "tasks-panel",
          "as": "planTasks",
          "entity": "task"
        },
        {
          "component": "entity-summary",
          "as": "planSummary"
        }
      ],
      "workflows": [
        {
          "name": "select_plan",
          "safety": "read",
          "description": "Open one of the patient's physiotherapy care plans from the plan list.",
          "descriptionKey": "ui.agent.physioCarePlanEditor.workflows.selectPlan",
          "uiActions": [],
          "apiActions": [
            "carePlan.get"
          ]
        },
        {
          "name": "add_plan",
          "safety": "write",
          "description": "Create a new physiotherapy care plan for the patient.",
          "descriptionKey": "ui.agent.physioCarePlanEditor.workflows.addPlan",
          "uiActions": [],
          "apiActions": [
            "carePlan.create"
          ]
        },
        {
          "name": "mark_session_done",
          "safety": "write",
          "description": "Mark a planned session as executed from its row action in the sessions grid.",
          "descriptionKey": "ui.agent.physioCarePlanEditor.workflows.markSessionDone",
          "uiActions": [],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": [
            "carePlanTreatment.update"
          ]
        },
        {
          "name": "add_session",
          "safety": "write",
          "description": "Add a planned session row to the current care plan.",
          "descriptionKey": "ui.agent.physioCarePlanEditor.workflows.addSession",
          "uiActions": [],
          "apiActions": [
            "carePlanTreatment.create"
          ]
        },
        {
          "name": "remove_session",
          "safety": "destructive",
          "description": "Remove the selected session(s) from the plan (read data-table.selection for the targets).",
          "descriptionKey": "ui.agent.physioCarePlanEditor.workflows.removeSession",
          "uiActions": [],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": [
            "carePlanTreatment.delete"
          ]
        },
        {
          "name": "save_plan",
          "safety": "write",
          "description": "Persist the current edits to the physiotherapy care plan.",
          "descriptionKey": "ui.agent.physioCarePlanEditor.workflows.savePlan",
          "uiActions": [],
          "apiActions": [
            "carePlan.update"
          ]
        },
        {
          "name": "add_plan_note",
          "safety": "phi",
          "description": "Add a note to the plan via the docked Notes tool. A clinical note requires the clinical-note permission.",
          "descriptionKey": "ui.agent.physioCarePlanEditor.workflows.addPlanNote",
          "uiActions": [
            "notes-panel.add_note"
          ],
          "apiActions": [
            "note.create"
          ]
        },
        {
          "name": "triage_plan_tasks",
          "safety": "write",
          "description": "Open or complete a follow-up task from the docked Tasks tool.",
          "descriptionKey": "ui.agent.physioCarePlanEditor.workflows.triagePlanTasks",
          "uiActions": [
            "tasks-panel.select_item",
            "tasks-panel.toggle_done"
          ],
          "stateReads": [
            "tasks-panel.items"
          ],
          "apiActions": [
            "task.update"
          ]
        },
        {
          "name": "regenerate_summary",
          "safety": "write",
          "description": "Regenerate the AI plan summary in the docked Plan summary tool.",
          "descriptionKey": "ui.agent.physioCarePlanEditor.workflows.regenerateSummary",
          "uiActions": [
            "entity-summary.regenerate"
          ],
          "apiActions": [
            "alia.summarise"
          ]
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "care-plans",
      "composes": [
        {
          "component": "data-table",
          "as": "register",
          "entity": "carePlan"
        },
        {
          "component": "button",
          "as": "newPlan"
        },
        {
          "component": "button",
          "as": "downloadCsv"
        },
        {
          "component": "icon-button-group",
          "as": "rowActions"
        },
        {
          "component": "transaction-chip",
          "as": "invoiceChip"
        },
        {
          "component": "smart-date",
          "as": "dueDate"
        },
        {
          "component": "counter",
          "as": "planRollupCount"
        },
        {
          "component": "card",
          "as": "gridCard"
        },
        {
          "component": "warning-stack",
          "as": "planWarnings"
        }
      ],
      "workflows": [
        {
          "name": "select_plans",
          "safety": "read",
          "description": "Select one or more plan or care rows in the register for a bulk action.",
          "descriptionKey": "ui.agent.carePlans.workflows.selectPlans",
          "uiActions": [
            "data-table.select_rows",
            "data-table.get_selection"
          ],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": []
        },
        {
          "name": "filter_by_period",
          "safety": "read",
          "description": "Filter the register to a created/scheduled date range via the per-column date filters.",
          "descriptionKey": "ui.agent.carePlans.workflows.filterByPeriod",
          "uiActions": [
            "data-table.apply_filter"
          ],
          "stateReads": [
            "data-table.filter"
          ],
          "apiActions": []
        },
        {
          "name": "create_plan",
          "safety": "write",
          "description": "Open the \"New plan\" action from the page header and persist a new treatment plan for the patient.",
          "descriptionKey": "ui.agent.carePlans.workflows.createPlan",
          "uiActions": [],
          "apiActions": [
            "carePlan.create"
          ]
        },
        {
          "name": "create_appointment_for_care",
          "safety": "write",
          "description": "From a planned care row action, schedule an appointment for that treatment.",
          "descriptionKey": "ui.agent.carePlans.workflows.createAppointmentForCare",
          "uiActions": [
            "data-table.get_selection"
          ],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": [
            "appointment.create"
          ]
        },
        {
          "name": "generate_invoice",
          "safety": "write",
          "description": "Bill a completed treatment: create the doctor bill / invoice the selected care sits on.",
          "descriptionKey": "ui.agent.carePlans.workflows.generateInvoice",
          "uiActions": [
            "data-table.get_selection"
          ],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": [
            "invoice.create",
            "carePlan.markBilled"
          ]
        },
        {
          "name": "export_csv",
          "safety": "read",
          "description": "Download the current filtered register as a CSV from the page header.",
          "descriptionKey": "ui.agent.carePlans.workflows.exportCsv",
          "uiActions": [],
          "apiActions": [
            "carePlan.export"
          ]
        },
        {
          "name": "delete_care",
          "safety": "destructive",
          "description": "Delete the selected non-billed care row from its plan. Irreversible.",
          "descriptionKey": "ui.agent.carePlans.workflows.deleteCare",
          "uiActions": [
            "data-table.get_selection",
            "data-table.clear_selection"
          ],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": [
            "carePlan.deleteCare"
          ]
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "confirm-phone",
      "composes": [
        {
          "component": "dialog",
          "as": "prompt"
        },
        {
          "component": "form-field",
          "as": "field"
        },
        {
          "component": "phone-input",
          "as": "mobileNumber"
        },
        {
          "component": "button",
          "as": "save"
        },
        {
          "component": "button",
          "as": "skip"
        }
      ],
      "workflows": [
        {
          "name": "enter_mobile_number",
          "safety": "write",
          "description": "Type or edit the mobile number (Italy-default dial code, editable) in the phone field.",
          "descriptionKey": "ui.agent.confirmPhone.workflows.enterMobileNumber",
          "uiActions": [
            "phone-input.set_value"
          ],
          "stateReads": [
            "phone-input.value",
            "phone-input.isEmpty"
          ],
          "apiActions": []
        },
        {
          "name": "confirm_mobile_number",
          "safety": "write",
          "description": "Save the entered mobile number, enabling the SMS two-factor path. An invalid or landline number keeps the prompt open with an inline error.",
          "descriptionKey": "ui.agent.confirmPhone.workflows.confirmMobileNumber",
          "uiActions": [
            "phone-input.set_value"
          ],
          "stateReads": [
            "phone-input.value"
          ],
          "apiActions": [
            "user.confirmMobileNumber"
          ]
        },
        {
          "name": "skip_prompt",
          "safety": "read",
          "description": "Dismiss the prompt without saving. Access continues; the prompt re-appears at the next login.",
          "descriptionKey": "ui.agent.confirmPhone.workflows.skipPrompt",
          "uiActions": [
            "dialog.dismiss"
          ],
          "stateReads": [
            "dialog.isOpen"
          ],
          "apiActions": []
        },
        {
          "name": "reopen_prompt",
          "safety": "read",
          "description": "Open the confirm-phone prompt again after it was skipped.",
          "descriptionKey": "ui.agent.confirmPhone.workflows.reopenPrompt",
          "uiActions": [
            "dialog.open"
          ],
          "stateReads": [
            "dialog.isOpen"
          ],
          "apiActions": []
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "dashboard",
      "composes": [
        {
          "component": "sidebar",
          "as": "nav"
        },
        {
          "component": "header",
          "as": "topbar"
        },
        {
          "component": "tool-rail",
          "as": "rail"
        },
        {
          "component": "warning-stack",
          "as": "attentionStrip",
          "entity": "notice"
        },
        {
          "component": "progress",
          "as": "efficiencyGauge"
        },
        {
          "component": "stat",
          "as": "actionTile",
          "entity": "metric"
        },
        {
          "component": "card",
          "as": "tileShell"
        },
        {
          "component": "button",
          "as": "quickCreate"
        },
        {
          "component": "empty-state",
          "as": "allCaughtUp"
        }
      ],
      "workflows": [
        {
          "name": "triage_warnings",
          "safety": "write",
          "description": "Review the outstanding-action notices and dismiss the ones that are handled. The strip folds away once every notice is cleared. Dismissal is delegated through the WarningStack item `onDismiss` callback, so there is no imperative ui action.",
          "descriptionKey": "ui.agent.dashboard.workflows.triageWarnings",
          "uiActions": [],
          "apiActions": [
            "notice.dismiss"
          ]
        },
        {
          "name": "open_inbox",
          "safety": "read",
          "description": "Open the inline-end AI tools rail to the Inbox tool to read the merged notifications / messages / product-update feed.",
          "descriptionKey": "ui.agent.dashboard.workflows.openInbox",
          "uiActions": [
            "tool-rail.open",
            "tool-rail.select_tool"
          ],
          "stateReads": [
            "tool-rail.activeToolId"
          ],
          "apiActions": [
            "inbox.list"
          ]
        },
        {
          "name": "quick_create",
          "safety": "write",
          "description": "Use a quick-entry tile CTA to start creating a new patient, appointment, treatment plan, or invoice.",
          "descriptionKey": "ui.agent.dashboard.workflows.quickCreate",
          "uiActions": [],
          "apiActions": [
            "patient.create",
            "appointment.create",
            "carePlan.create",
            "invoice.create"
          ]
        },
        {
          "name": "navigate_section",
          "safety": "read",
          "description": "Jump to another workspace section (patients, schedule, documents, settings) from the Sidebar.",
          "descriptionKey": "ui.agent.dashboard.workflows.navigateSection",
          "uiActions": [
            "sidebar.toggle_collapsed"
          ],
          "stateReads": [
            "sidebar.isCollapsed"
          ],
          "apiActions": [
            "navigation.go"
          ]
        },
        {
          "name": "review_efficiency",
          "safety": "read",
          "description": "Read the Studio efficiency gauge and open the settings checklist to complete the remaining configuration steps.",
          "descriptionKey": "ui.agent.dashboard.workflows.reviewEfficiency",
          "uiActions": [],
          "apiActions": [
            "practiceSettings.checklist"
          ]
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "error-page",
      "composes": [
        {
          "component": "logo",
          "as": "brand"
        },
        {
          "component": "button",
          "as": "retry"
        },
        {
          "component": "button",
          "as": "home"
        },
        {
          "component": "button",
          "as": "login"
        },
        {
          "component": "button",
          "as": "support"
        },
        {
          "component": "button",
          "as": "custom"
        }
      ],
      "workflows": [
        {
          "name": "read_error",
          "safety": "read",
          "description": "Read which error the visitor hit (`data-status` on the root), what it means and the reference to quote to support, if shown.",
          "descriptionKey": "ui.agent.errorPage.workflows.readError",
          "uiActions": [],
          "apiActions": []
        },
        {
          "name": "retry",
          "safety": "write",
          "description": "Try again (`data-action=\"retry\"`). By default this reloads the page. Inside an app the host may handle it instead and send the failed request again, such as a booking confirmation, so it counts as a write.",
          "descriptionKey": "ui.agent.errorPage.workflows.retry",
          "uiActions": [],
          "apiActions": []
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "forgot-password-form",
      "composes": [
        {
          "component": "card",
          "as": "card"
        },
        {
          "component": "alert",
          "as": "formError"
        },
        {
          "component": "error-summary",
          "as": "errorSummary"
        },
        {
          "component": "alert",
          "as": "confirmation"
        },
        {
          "component": "form-field",
          "as": "field"
        },
        {
          "component": "email-input",
          "as": "email"
        },
        {
          "component": "button",
          "as": "submit"
        }
      ],
      "workflows": [
        {
          "name": "read_form",
          "safety": "read",
          "description": "Read where the request stands. The root carries `data-state`: `asking` while the form shows, `sent` once the confirmation has taken its place (`data-slot=\"confirmation\"`). While asking, the email sits in `data-field=\"email\"`, with `aria-invalid=\"true\"` on its control and its message in a `data-slot=\"error\"` element when it has a problem, also listed in `data-component=\"error-summary\"` after a refused submit; a message about the whole request is in `data-field=\"form\"`. The confirmation is the same for every address: it does not say whether an account exists.",
          "descriptionKey": "ui.agent.forgotPasswordForm.workflows.readForm",
          "uiActions": [],
          "apiActions": []
        },
        {
          "name": "request_reset_link",
          "safety": "write",
          "description": "Ask for a password reset link (`data-action=\"submit\"`). The person types the email themselves; the form does not submit until it is a valid address. The host then sends the link, through its `onSubmit` handler or a native form post, and shows the confirmation for every address, whether or not an account exists for it.",
          "descriptionKey": "ui.agent.forgotPasswordForm.workflows.requestResetLink",
          "uiActions": [],
          "apiActions": [
            "auth.requestPasswordReset"
          ]
        },
        {
          "name": "back_to_sign_in",
          "safety": "read",
          "description": "Go back to the sign-in page (`data-action=\"login\"`). Present only when the host gives its address.",
          "descriptionKey": "ui.agent.forgotPasswordForm.workflows.backToSignIn",
          "uiActions": [],
          "apiActions": []
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "help-me-write-templates",
      "composes": [
        {
          "component": "rich-text-editor",
          "as": "editor"
        },
        {
          "component": "editor-overlay",
          "as": "assistantBar"
        },
        {
          "component": "text-area",
          "as": "prompt"
        },
        {
          "component": "dropdown-menu",
          "as": "templatesMenu",
          "entity": "template"
        },
        {
          "component": "dialog",
          "as": "templateManager",
          "entity": "template"
        },
        {
          "component": "dialog",
          "as": "deleteConfirmation",
          "entity": "template"
        },
        {
          "component": "alert",
          "as": "creditsExhausted"
        },
        {
          "component": "alert",
          "as": "undoNotice"
        }
      ],
      "workflows": [
        {
          "name": "run_template",
          "safety": "phi",
          "description": "Open the Templates menu from the editor's AI pill, or from the bubble that appears over selected text, and pick a template (listed in the practice's order). It runs straight away and rewrites the selected text, or the whole note when nothing is selected; the notice that follows offers Undo. Without patient AI consent the consent banner shows first. Out of AI credits opens the Alia Writing Assistant on the out-of-credits notice.",
          "descriptionKey": "ui.agent.helpMeWriteTemplates.workflows.runTemplate",
          "uiActions": [
            "dropdown-menu.open",
            "dropdown-menu.close"
          ],
          "stateReads": [
            "dropdown-menu.isOpen"
          ],
          "apiActions": [
            "aiTemplate.generate"
          ]
        },
        {
          "name": "free_prompt",
          "safety": "phi",
          "description": "Type (or dictate with the bar mic) what to write and press Write; the draft is inserted at the caret on Insert.",
          "descriptionKey": "ui.agent.helpMeWriteTemplates.workflows.freePrompt",
          "uiActions": [],
          "apiActions": [
            "aiTemplate.generate"
          ]
        },
        {
          "name": "manage_templates",
          "safety": "write",
          "description": "Open Manage templates from the Templates menu in the AI pill: list the practice's templates, create or edit one (name, optional short description, instructions for the AI; names are unique), reorder them by dragging and delete one after a confirmation. Shown only when the host allows managing.",
          "descriptionKey": "ui.agent.helpMeWriteTemplates.workflows.manageTemplates",
          "uiActions": [
            "dialog.close",
            "dialog.dismiss"
          ],
          "stateReads": [
            "dialog.isOpen"
          ],
          "apiActions": [
            "aiTemplate.save",
            "aiTemplate.delete"
          ]
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "invoices",
      "composes": [
        {
          "component": "data-table",
          "as": "ledger",
          "entity": "invoice"
        },
        {
          "component": "icon-button-group",
          "as": "tableActions"
        },
        {
          "component": "icon-button",
          "as": "tableAction"
        },
        {
          "component": "badge",
          "as": "statusBadge"
        },
        {
          "component": "button",
          "as": "rowAction"
        }
      ],
      "workflows": [
        {
          "name": "filter_invoices",
          "safety": "read",
          "description": "Narrow the ledger by number, relation, status, date range or amount using the per-column filters.",
          "descriptionKey": "ui.agent.invoices.workflows.filterInvoices",
          "uiActions": [
            "data-table.apply_filter"
          ],
          "stateReads": [
            "data-table.filter"
          ],
          "apiActions": [
            "invoice.list"
          ]
        },
        {
          "name": "sort_ledger",
          "safety": "read",
          "description": "Re-sort the ledger by any column (e.g. issue date, total, balance).",
          "descriptionKey": "ui.agent.invoices.workflows.sortLedger",
          "uiActions": [
            "data-table.sort_by"
          ],
          "stateReads": [
            "data-table.sort"
          ],
          "apiActions": []
        },
        {
          "name": "paginate",
          "safety": "read",
          "description": "Move to another page of the ledger.",
          "descriptionKey": "ui.agent.invoices.workflows.paginate",
          "uiActions": [
            "data-table.go_to_page"
          ],
          "stateReads": [
            "data-table.currentPage"
          ],
          "apiActions": []
        },
        {
          "name": "export_ledger",
          "safety": "read",
          "description": "Export the current (optionally filtered) ledger from the page-header table-tools cluster — CSV / Excel / PDF.",
          "descriptionKey": "ui.agent.invoices.workflows.exportLedger",
          "uiActions": [],
          "apiActions": [
            "invoice.export"
          ]
        },
        {
          "name": "view_invoice",
          "safety": "read",
          "description": "Open a single invoice from its row action to inspect line items and payment history.",
          "descriptionKey": "ui.agent.invoices.workflows.viewInvoice",
          "uiActions": [
            "data-table.get_selection"
          ],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": [
            "invoice.get"
          ]
        },
        {
          "name": "download_pdf",
          "safety": "read",
          "description": "Download the selected invoice as a PDF from its row action.",
          "descriptionKey": "ui.agent.invoices.workflows.downloadPdf",
          "uiActions": [
            "data-table.get_selection"
          ],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": [
            "invoice.downloadPdf"
          ]
        },
        {
          "name": "send_reminder",
          "safety": "write",
          "description": "Send a payment reminder for the selected invoice through its eligible channel (email or SMS).",
          "descriptionKey": "ui.agent.invoices.workflows.sendReminder",
          "uiActions": [
            "data-table.get_selection"
          ],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": [
            "invoice.sendReminder"
          ]
        },
        {
          "name": "delete_invoice",
          "safety": "destructive",
          "description": "Delete the selected invoice from its row action. Paid invoices cannot be deleted. Irreversible.",
          "descriptionKey": "ui.agent.invoices.workflows.deleteInvoice",
          "uiActions": [
            "data-table.get_selection",
            "data-table.clear_selection"
          ],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": [
            "invoice.delete"
          ]
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "login-form",
      "composes": [
        {
          "component": "card",
          "as": "card"
        },
        {
          "component": "alert",
          "as": "formError"
        },
        {
          "component": "error-summary",
          "as": "errorSummary"
        },
        {
          "component": "form-field",
          "as": "field"
        },
        {
          "component": "email-input",
          "as": "email"
        },
        {
          "component": "password-input",
          "as": "password"
        },
        {
          "component": "checkbox",
          "as": "rememberMe"
        },
        {
          "component": "button",
          "as": "submit"
        },
        {
          "component": "matrix-rain",
          "as": "devCardBackdrop"
        }
      ],
      "workflows": [
        {
          "name": "read_form",
          "safety": "read",
          "description": "Read the sign-in form and what is wrong with it. Each field sits in a wrapper with `data-field` (`email`, `password`, and `remember-me` when the host turns it on). A field with a problem has `aria-invalid=\"true\"` on its control and its message in a `data-slot=\"error\"` element inside the wrapper. After a refused submit the fields with a problem are also listed in `data-component=\"error-summary\"` at the top of the form, one item per field (`data-error-field`). A message about the whole form, such as a refused sign-in, is in `data-field=\"form\"`; it never says which of the two values was wrong. Never read or repeat the password.",
          "descriptionKey": "ui.agent.loginForm.workflows.readForm",
          "uiActions": [],
          "apiActions": []
        },
        {
          "name": "sign_in",
          "safety": "write",
          "description": "Sign in (`data-action=\"submit\"`). The person types the email and the password themselves; the form does not submit until the email field is filled in and the password is not empty; text with an `@` must be a valid email address, and text without one is accepted as a username only when the host sets `allowUsername`; it lists what is wrong in its error summary and moves focus there. The host then signs the person in: through its `onSubmit` handler, or as a native form post to its own field names.",
          "descriptionKey": "ui.agent.loginForm.workflows.signIn",
          "uiActions": [],
          "apiActions": [
            "auth.signIn"
          ]
        },
        {
          "name": "remember_me",
          "safety": "write",
          "description": "Tick or untick \"Remember me on this computer\" (`data-field=\"remember-me\"`, a checkbox, unticked by default). Present only when the host turns it on. It reports the choice to the host, which decides what it means; it changes nothing until the form is submitted.",
          "descriptionKey": "ui.agent.loginForm.workflows.rememberMe",
          "uiActions": [],
          "apiActions": []
        },
        {
          "name": "forgot_password",
          "safety": "read",
          "description": "Go to the page that asks for a password reset link (`data-action=\"forgot-password\"`). Present only when the host gives its address.",
          "descriptionKey": "ui.agent.loginForm.workflows.forgotPassword",
          "uiActions": [],
          "apiActions": []
        },
        {
          "name": "register",
          "safety": "read",
          "description": "Go to a registration page: `data-action=\"register-doctor\"` or `data-action=\"register-patient\"`, under the sign-in button. Each is present only when the host gives its address.",
          "descriptionKey": "ui.agent.loginForm.workflows.register",
          "uiActions": [],
          "apiActions": []
        },
        {
          "name": "dev_sign_in",
          "safety": "write",
          "description": "Development only: follow one of the quick sign-in links (`data-action=\"dev-login\"`, inside `data-component=\"login-dev-card\"`). Each leads to a route on the host that signs a test account in. The kit holds no test data. The card is present only when the host's server reports a development environment, and the server refuses those routes anywhere else.",
          "descriptionKey": "ui.agent.loginForm.workflows.devSignIn",
          "uiActions": [],
          "apiActions": []
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "marketplace-app-shell",
      "composes": [
        {
          "component": "app-frame",
          "as": "frame"
        },
        {
          "component": "header",
          "as": "topBar"
        },
        {
          "component": "sidebar",
          "as": "mainNav",
          "entity": "navItem"
        },
        {
          "component": "tab-bar",
          "as": "embeddedNav",
          "entity": "navItem"
        },
        {
          "component": "avatar",
          "as": "accountAvatar"
        },
        {
          "component": "dropdown-menu",
          "as": "accountMenu"
        },
        {
          "component": "header-settings",
          "as": "settings"
        },
        {
          "component": "sign-in-with-alfadocs-button",
          "as": "connectCta"
        },
        {
          "component": "alert",
          "as": "connectError"
        },
        {
          "component": "card",
          "as": "contentSurface"
        },
        {
          "component": "theme-root",
          "as": "themeScope"
        },
        {
          "component": "tooltip",
          "as": "navTooltip"
        }
      ],
      "workflows": [
        {
          "name": "navigate",
          "safety": "read",
          "description": "Navigate to one of the app sections via the sidebar nav (or the embedded tab strip). Routing is consumer-owned, so the destination resolves through the host router.",
          "descriptionKey": "ui.agent.marketplaceAppShell.workflows.navigate",
          "uiActions": [],
          "apiActions": [
            "app.navigate"
          ]
        },
        {
          "name": "toggle_sidebar",
          "safety": "read",
          "description": "Collapse or expand the main navigation rail and read its current collapsed state.",
          "descriptionKey": "ui.agent.marketplaceAppShell.workflows.toggleSidebar",
          "uiActions": [
            "sidebar.toggle_collapsed"
          ],
          "stateReads": [
            "sidebar.isCollapsed"
          ],
          "apiActions": []
        },
        {
          "name": "open_account_menu",
          "safety": "read",
          "description": "Open the account dropdown to reach sign-out and account settings.",
          "descriptionKey": "ui.agent.marketplaceAppShell.workflows.openAccountMenu",
          "uiActions": [
            "dropdown-menu.open"
          ],
          "stateReads": [
            "dropdown-menu.isOpen"
          ],
          "apiActions": []
        },
        {
          "name": "set_appearance",
          "safety": "write",
          "description": "Change the active theme, locale, or accessibility profile from the header settings.",
          "descriptionKey": "ui.agent.marketplaceAppShell.workflows.setAppearance",
          "uiActions": [
            "header-settings.set_theme",
            "header-settings.set_locale",
            "header-settings.set_accessibility"
          ],
          "stateReads": [
            "header-settings.theme",
            "header-settings.locale",
            "header-settings.accessibility",
            "header-settings.resolvedTheme"
          ],
          "apiActions": [
            "preferences.update"
          ]
        },
        {
          "name": "connect_account",
          "safety": "write",
          "description": "Start the AlfaDocs OAuth connect flow from the pre-auth screen. Persists an authorised session.",
          "descriptionKey": "ui.agent.marketplaceAppShell.workflows.connectAccount",
          "uiActions": [],
          "apiActions": [
            "auth.connect"
          ]
        },
        {
          "name": "sign_out",
          "safety": "write",
          "description": "Sign out of the connected AlfaDocs account from the account menu. Ends the session.",
          "descriptionKey": "ui.agent.marketplaceAppShell.workflows.signOut",
          "uiActions": [
            "dropdown-menu.open"
          ],
          "apiActions": [
            "auth.signOut"
          ]
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "patient-ai-summary",
      "composes": [
        {
          "component": "tool-rail",
          "as": "toolRail"
        },
        {
          "component": "accordion",
          "as": "briefSections",
          "entity": "patientSection"
        },
        {
          "component": "patient-summary-card",
          "as": "overview",
          "entity": "patient"
        },
        {
          "component": "appointment-card",
          "as": "nextAppointment",
          "entity": "appointment"
        },
        {
          "component": "anamnesis-card",
          "as": "medicalHistory",
          "entity": "anamnesis"
        },
        {
          "component": "clinical-note-card",
          "as": "latestNote",
          "entity": "clinicalNote"
        },
        {
          "component": "care-plan-card",
          "as": "activePlan",
          "entity": "carePlan"
        },
        {
          "component": "payment-card",
          "as": "latestPayment",
          "entity": "payment"
        },
        {
          "component": "ai-consent-banner",
          "as": "consentGate"
        }
      ],
      "workflows": [
        {
          "name": "open_tool",
          "safety": "read",
          "description": "Open one of the rail tools — the Patient Summary brief or the Ask Alia chat — making its panel the open region inside the rail landmark.",
          "descriptionKey": "ui.agent.patientAiSummary.workflows.openTool",
          "uiActions": [
            "tool-rail.open",
            "tool-rail.select_tool"
          ],
          "stateReads": [
            "tool-rail.activeToolId"
          ],
          "apiActions": []
        },
        {
          "name": "read_brief",
          "safety": "read",
          "description": "Read the compiled patient brief — overview counts/flags, plan state and progress, and the latest payment record.",
          "descriptionKey": "ui.agent.patientAiSummary.workflows.readBrief",
          "uiActions": [],
          "stateReads": [
            "patient-summary-card.summary",
            "care-plan-card.state",
            "care-plan-card.progress",
            "payment-card.state"
          ],
          "apiActions": [
            "patient.summarise"
          ]
        },
        {
          "name": "expand_section",
          "safety": "read",
          "description": "Expand one section of the brief accordion (overview, appointment, history, plan, or attention) to reveal its entity card.",
          "descriptionKey": "ui.agent.patientAiSummary.workflows.expandSection",
          "uiActions": [
            "accordion.expand",
            "accordion.collapse"
          ],
          "stateReads": [
            "accordion.openItems"
          ],
          "apiActions": []
        },
        {
          "name": "grant_ai_consent",
          "safety": "write",
          "description": "Record the patient AI-assistance consent that gates the brief, revealing the structured summary once granted.",
          "descriptionKey": "ui.agent.patientAiSummary.workflows.grantAiConsent",
          "uiActions": [],
          "stateReads": [
            "ai-consent-banner.consentState",
            "ai-consent-banner.armed"
          ],
          "apiActions": [
            "patient.grantAiConsent"
          ]
        },
        {
          "name": "ask_alia",
          "safety": "write",
          "description": "Open the Ask Alia tool and send a question about this patient; Alia can answer with an in-conversation entity card.",
          "descriptionKey": "ui.agent.patientAiSummary.workflows.askAlia",
          "uiActions": [
            "tool-rail.select_tool"
          ],
          "stateReads": [
            "tool-rail.activeToolId"
          ],
          "apiActions": [
            "alia.sendMessage"
          ]
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "patient-check-in",
      "composes": [
        {
          "component": "qr-code",
          "as": "checkInQr"
        },
        {
          "component": "locale-picker",
          "as": "languagePicker"
        },
        {
          "component": "social-sign-in-button",
          "as": "ssoSignIn"
        },
        {
          "component": "email-input",
          "as": "signInEmail"
        },
        {
          "component": "phone-input",
          "as": "signInPhone"
        },
        {
          "component": "otp-input",
          "as": "verifyCode"
        },
        {
          "component": "card",
          "as": "appointmentHub",
          "entity": "appointment"
        },
        {
          "component": "dependent-selector",
          "as": "whoIsCheckingIn",
          "entity": "person"
        },
        {
          "component": "form-field",
          "as": "detailsField"
        },
        {
          "component": "text-input",
          "as": "detailsName"
        },
        {
          "component": "fiscal-code-input",
          "as": "detailsFiscalCode"
        },
        {
          "component": "address-autocomplete",
          "as": "detailsAddress"
        },
        {
          "component": "date-picker",
          "as": "detailsBirthDate"
        },
        {
          "component": "select",
          "as": "detailsCountry"
        },
        {
          "component": "radio-group",
          "as": "detailsGender"
        },
        {
          "component": "document-scanner",
          "as": "idCapture"
        },
        {
          "component": "file-upload",
          "as": "idUpload"
        },
        {
          "component": "sign-document",
          "as": "consentDoc"
        },
        {
          "component": "signature-capture",
          "as": "consentSignature"
        },
        {
          "component": "payment-form",
          "as": "visitPayment"
        },
        {
          "component": "wallet-pay-button",
          "as": "walletPay"
        },
        {
          "component": "session-countdown",
          "as": "sessionGuard"
        },
        {
          "component": "alert",
          "as": "statusNotice"
        },
        {
          "component": "badge",
          "as": "appointmentBadge"
        },
        {
          "component": "separator",
          "as": "stepDivider"
        }
      ],
      "workflows": [
        {
          "name": "sign_in_with_code",
          "safety": "write",
          "description": "Request a one-time SMS/email code, enter it, and authenticate into the check-in flow.",
          "descriptionKey": "ui.agent.patientCheckIn.workflows.signInWithCode",
          "uiActions": [
            "otp-input.set_value"
          ],
          "stateReads": [
            "otp-input.isComplete",
            "email-input.value"
          ],
          "apiActions": [
            "auth.requestOtp",
            "auth.verifyOtp"
          ]
        },
        {
          "name": "set_language",
          "safety": "read",
          "description": "Pick the kiosk language for the check-in session.",
          "descriptionKey": "ui.agent.patientCheckIn.workflows.setLanguage",
          "uiActions": [
            "locale-picker.set_locale"
          ],
          "apiActions": []
        },
        {
          "name": "select_subject",
          "safety": "write",
          "description": "Choose who is checking in (self or a dependent) and confirm their personal data.",
          "descriptionKey": "ui.agent.patientCheckIn.workflows.selectSubject",
          "uiActions": [
            "dependent-selector.set_value",
            "text-input.set_value",
            "fiscal-code-input.set_value",
            "address-autocomplete.set_value",
            "date-picker.set_date",
            "select.set_value",
            "radio-group.set_value"
          ],
          "stateReads": [
            "dependent-selector.value",
            "fiscal-code-input.isValid"
          ],
          "apiActions": [
            "patient.updateDetails"
          ]
        },
        {
          "name": "capture_id_document",
          "safety": "write",
          "description": "Photograph or upload the health card / ID document for the visit.",
          "descriptionKey": "ui.agent.patientCheckIn.workflows.captureIdDocument",
          "uiActions": [
            "document-scanner.start_camera",
            "document-scanner.capture",
            "document-scanner.submit",
            "file-upload.clear"
          ],
          "stateReads": [
            "document-scanner.hasCapture",
            "file-upload.files"
          ],
          "apiActions": [
            "document.upload"
          ]
        },
        {
          "name": "sign_consents",
          "safety": "write",
          "description": "Read each consent form, add the signature, and submit the signed consents.",
          "descriptionKey": "ui.agent.patientCheckIn.workflows.signConsents",
          "uiActions": [
            "signature-capture.confirm",
            "signature-capture.clear",
            "sign-document.submit"
          ],
          "stateReads": [
            "signature-capture.isEmpty",
            "sign-document.isReadComplete"
          ],
          "apiActions": [
            "consent.sign"
          ]
        },
        {
          "name": "pay_for_visit",
          "safety": "write",
          "description": "Pay the visit fee by card or digital wallet.",
          "descriptionKey": "ui.agent.patientCheckIn.workflows.payForVisit",
          "uiActions": [
            "payment-form.submit"
          ],
          "apiActions": [
            "payment.charge"
          ]
        },
        {
          "name": "complete_check_in",
          "safety": "write",
          "description": "Finalise the check-in once all steps are done; marks the patient as arrived.",
          "descriptionKey": "ui.agent.patientCheckIn.workflows.completeCheckIn",
          "uiActions": [],
          "apiActions": [
            "appointment.checkIn"
          ]
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "patient-folder",
      "composes": [
        {
          "component": "app-frame",
          "as": "frame"
        },
        {
          "component": "header",
          "as": "appHeader"
        },
        {
          "component": "sidebar",
          "as": "appNav"
        },
        {
          "component": "control-room-rail",
          "as": "controlRoom"
        },
        {
          "component": "tab-bar",
          "as": "sectionNav",
          "entity": "section"
        },
        {
          "component": "patient-summary-card",
          "as": "patientBanner"
        },
        {
          "component": "empty-state",
          "as": "placeholderSection"
        },
        {
          "component": "patient-details",
          "as": "patientDetailsTool"
        },
        {
          "component": "notes-panel",
          "as": "patientNotes",
          "entity": "note"
        },
        {
          "component": "appointment-timeline",
          "as": "patientAppointments",
          "entity": "appointment"
        },
        {
          "component": "tasks-panel",
          "as": "patientTasks",
          "entity": "task"
        },
        {
          "component": "care-plan-header",
          "as": "planHeader"
        },
        {
          "component": "tooth-scheme",
          "as": "odontogram",
          "entity": "tooth"
        },
        {
          "component": "data-table",
          "as": "treatmentsGrid",
          "entity": "treatment"
        },
        {
          "component": "entity-summary",
          "as": "planSummaryTool"
        },
        {
          "component": "radiograph-panel",
          "as": "radiographsTool",
          "entity": "radiograph"
        },
        {
          "component": "tabs",
          "as": "anamnesisViews"
        },
        {
          "component": "file-manager",
          "as": "documents",
          "entity": "document"
        },
        {
          "component": "document-preview",
          "as": "documentPreviewTool"
        },
        {
          "component": "button",
          "as": "documentsToSign"
        },
        {
          "component": "dialog",
          "as": "signatureRequestModal"
        },
        {
          "component": "chat-container",
          "as": "messageThread"
        },
        {
          "component": "chat-message",
          "as": "messageBubble",
          "entity": "message"
        },
        {
          "component": "chat-input",
          "as": "messageComposer"
        },
        {
          "component": "select",
          "as": "channelPicker"
        },
        {
          "component": "badge",
          "as": "deliveryStatus"
        },
        {
          "component": "button",
          "as": "enableChannel"
        },
        {
          "component": "avatar",
          "as": "speakerAvatar"
        }
      ],
      "workflows": [
        {
          "name": "open_section",
          "safety": "read",
          "description": "Switch the folder to one of its section tabs — Anamnesis, Diagnosis, Care Plan, Communications, Documents or Bills — swapping the panel in place beneath the persistent patient banner. The banner and the four patient-level Control Room tools stay put across the switch. TabBar's active tab is a consumer-owned prop with no adapter action, so activation is a native click on the section button. View state only.",
          "descriptionKey": "ui.agent.patientFolder.workflows.openSection",
          "uiActions": [],
          "apiActions": []
        },
        {
          "name": "read_patient_banner",
          "safety": "read",
          "description": "Read the structural summary the persistent patient banner carries — unsigned-document and highlighted-anamnesis counts, unpaid-balance and AI-consent flags — to decide what the folder needs attention on. Identifiers, counts and flags only; never patient identity or clinical content.",
          "descriptionKey": "ui.agent.patientFolder.workflows.readPatientBanner",
          "uiActions": [],
          "stateReads": [
            "patient-summary-card.summary"
          ],
          "apiActions": [
            "patient.get"
          ]
        },
        {
          "name": "customise_patient_fields",
          "safety": "read",
          "description": "Choose which demographic, contact and address fields the folder shows, and in what order. The banner's field cog and the rail's Patient details tool share one field catalogue, so the choice applies to both. View state only — no patient data is written.",
          "descriptionKey": "ui.agent.patientFolder.workflows.customisePatientFields",
          "uiActions": [
            "patient-details.set_visible_fields",
            "patient-details.set_field_order"
          ],
          "stateReads": [
            "patient-details.visibleFieldOrder"
          ],
          "apiActions": []
        },
        {
          "name": "open_patient_tool",
          "safety": "read",
          "description": "Open, switch or close one of the Control Room tools docked in the inline-end rail. The four patient-level tools — Patient details, Notes, Appointments, Tasks — are folder-owned and available on every section tab; the section-scoped ones (Plan summary and Radiographs on Care Plan, Document preview on Documents) come and go with the active tab. View state only.",
          "descriptionKey": "ui.agent.patientFolder.workflows.openPatientTool",
          "uiActions": [
            "control-room-rail.open",
            "control-room-rail.select_tool",
            "control-room-rail.close"
          ],
          "stateReads": [
            "control-room-rail.activeToolId"
          ],
          "apiActions": []
        },
        {
          "name": "update_patient_details",
          "safety": "phi",
          "description": "Correct a patient demographic or contact field inline in the rail's Patient details tool — sex, date of birth, place of birth, fiscal code, profession, phone, email, address. Writes patient-identifiable data.",
          "descriptionKey": "ui.agent.patientFolder.workflows.updatePatientDetails",
          "uiActions": [
            "control-room-rail.select_tool",
            "patient-details.update_field"
          ],
          "stateReads": [
            "patient-details.patientId"
          ],
          "apiActions": [
            "patient.update"
          ]
        },
        {
          "name": "add_patient_note",
          "safety": "phi",
          "description": "Add a note to the patient from the folder's Notes tool. The folder has exactly ONE Notes tool, shared by every section tab, so a note filed from any tab lands on the same timeline. A clinical note requires the clinical-note permission — read it before writing. Writes patient-identifiable clinical content.",
          "descriptionKey": "ui.agent.patientFolder.workflows.addPatientNote",
          "uiActions": [
            "control-room-rail.select_tool",
            "notes-panel.add_note"
          ],
          "stateReads": [
            "notes-panel.canAddClinical",
            "notes-panel.notes"
          ],
          "apiActions": [
            "note.create"
          ]
        },
        {
          "name": "open_visit_note",
          "safety": "read",
          "description": "Open the note recorded at one visit from the Diagnosis tab's evolution grid. The folder owns the address: the tab hands the visit's note id out and the folder routes it into its own Notes tool, which scrolls to and focuses that note — no second panel opens, so the note lives in exactly one place. Pressing the same marker again re-scrolls it. Read-only.",
          "descriptionKey": "ui.agent.patientFolder.workflows.openVisitNote",
          "uiActions": [
            "control-room-rail.select_tool"
          ],
          "stateReads": [
            "notes-panel.currentNoteId",
            "control-room-rail.activeToolId"
          ],
          "apiActions": []
        },
        {
          "name": "review_patient_appointments",
          "safety": "read",
          "description": "Read the patient's appointment timeline in the rail — past and upcoming visits — and jump to today or focus one appointment. Read-only; booking happens in the Appointments context, not the folder.",
          "descriptionKey": "ui.agent.patientFolder.workflows.reviewPatientAppointments",
          "uiActions": [
            "control-room-rail.select_tool",
            "appointment-timeline.select_item",
            "appointment-timeline.jump_to_today"
          ],
          "stateReads": [
            "appointment-timeline.items"
          ],
          "apiActions": [
            "appointment.list"
          ]
        },
        {
          "name": "triage_patient_tasks",
          "safety": "write",
          "description": "Work the patient's follow-up tasks in the rail: filter the list, jump to what is overdue, open a task or tick it done.",
          "descriptionKey": "ui.agent.patientFolder.workflows.triagePatientTasks",
          "uiActions": [
            "control-room-rail.select_tool",
            "tasks-panel.set_filter",
            "tasks-panel.jump_to_overdue",
            "tasks-panel.select_item",
            "tasks-panel.toggle_done"
          ],
          "stateReads": [
            "tasks-panel.items"
          ],
          "apiActions": [
            "task.update"
          ]
        },
        {
          "name": "review_care_plan",
          "safety": "read",
          "description": "Read the patient's open care plan in the Care Plan tab — the plan header's lifecycle state and alerts, the charted odontogram, the treatments grid and the rail's plan summary. The folder mounts the shared care-plan-editor surface with its own patient card suppressed, so the folder banner remains the only patient header. Editing the plan is the Care Plan Editor pattern's contract, not the folder's.",
          "descriptionKey": "ui.agent.patientFolder.workflows.reviewCarePlan",
          "uiActions": [
            "tooth-scheme.focus_tooth",
            "tooth-scheme.get_tooth",
            "data-table.select_rows",
            "data-table.sort_by"
          ],
          "stateReads": [
            "care-plan-header.state",
            "care-plan-header.alertCount",
            "tooth-scheme.chart",
            "data-table.selection",
            "entity-summary.sections"
          ],
          "apiActions": [
            "carePlan.get"
          ]
        },
        {
          "name": "open_tooth_radiographs",
          "safety": "read",
          "description": "Open the films charted against one tooth. This is a folder-specific seam: clicking a tooth on the odontogram routes that tooth's radiographs into the FOLDER's Control Room rail (alongside the pinned patient tools) rather than into a plan-local drawer. Read-only.",
          "descriptionKey": "ui.agent.patientFolder.workflows.openToothRadiographs",
          "uiActions": [
            "tooth-scheme.open_radiographs",
            "control-room-rail.select_tool",
            "radiograph-panel.view_radiograph",
            "radiograph-panel.close_viewer"
          ],
          "stateReads": [
            "tooth-scheme.teethWithRadiographs",
            "radiograph-panel.radiographs"
          ],
          "apiActions": [
            "radiograph.list"
          ]
        },
        {
          "name": "review_anamnesis",
          "safety": "read",
          "description": "Read the patient's anamnesis from the folder: the Anamnesis tab mounts the tool's intake surface (the pre-visit questionnaire) and the Diagnosis tab mounts its compile surface (the diagnostic record plus the across-visits evolution grid), both embedded so they sit flush under the folder header. Switch between the tool's own summary / compile / evolution views. Recording measurements, targets and answers is the Anamnesis pattern's contract, not the folder's.",
          "descriptionKey": "ui.agent.patientFolder.workflows.reviewAnamnesis",
          "uiActions": [
            "tabs.select_tab"
          ],
          "stateReads": [
            "tabs.activeTab"
          ],
          "apiActions": [
            "anamnesis.get"
          ]
        },
        {
          "name": "browse_documents",
          "safety": "read",
          "description": "Navigate the patient's document tree in the Documents tab: open a folder, filter by document type, and select files. Reads structural metadata only — ids, kinds, sizes, dates, document types and signature states. Document NAMES can identify a patient and are not returned here.",
          "descriptionKey": "ui.agent.patientFolder.workflows.browseDocuments",
          "uiActions": [
            "file-manager.navigate",
            "file-manager.set_type_filter",
            "file-manager.select_items",
            "file-manager.clear_selection"
          ],
          "stateReads": [
            "file-manager.currentFolder",
            "file-manager.typeFilter",
            "file-manager.selection",
            "file-manager.items"
          ],
          "apiActions": [
            "document.list"
          ]
        },
        {
          "name": "preview_document",
          "safety": "read",
          "description": "Open a document into the Control Room rail's Document preview. Single-clicking one file previews it; selecting two or more surfaces them as a tabbed preview. Reads only which render branch is active (pdf, image, metadata or empty) — never the document name. Read-only; nothing is downloaded or shared.",
          "descriptionKey": "ui.agent.patientFolder.workflows.previewDocument",
          "uiActions": [
            "file-manager.open_item",
            "control-room-rail.select_tool"
          ],
          "stateReads": [
            "document-preview.kind",
            "file-manager.selection"
          ],
          "apiActions": [
            "document.get"
          ]
        },
        {
          "name": "identify_documents",
          "safety": "phi",
          "description": "Resolve the display names of the selected documents, or of the one in the rail preview, when the agent must name a file back to the user. Document names routinely identify a patient, so this is the deliberate, audited read — every other document readback stays name-free.",
          "descriptionKey": "ui.agent.patientFolder.workflows.identifyDocuments",
          "uiActions": [
            "file-manager.get_item_names",
            "document-preview.get_name"
          ],
          "stateReads": [
            "file-manager.selection"
          ],
          "apiActions": []
        },
        {
          "name": "upload_document",
          "safety": "phi",
          "description": "Upload one or more files into the open folder of the patient's document tree. Writes a patient-identifiable document.",
          "descriptionKey": "ui.agent.patientFolder.workflows.uploadDocument",
          "uiActions": [
            "file-manager.navigate"
          ],
          "stateReads": [
            "file-manager.currentFolder",
            "file-manager.activeAction"
          ],
          "apiActions": [
            "document.upload"
          ]
        },
        {
          "name": "organise_documents",
          "safety": "write",
          "description": "Reorganise the document tree: create a folder, rename an item, or move the selected items into another folder. Only one of these action dialogs can be in flight at a time — read the active action before starting another. Reversible through the same toolbar.",
          "descriptionKey": "ui.agent.patientFolder.workflows.organiseDocuments",
          "uiActions": [
            "file-manager.select_items",
            "file-manager.navigate"
          ],
          "stateReads": [
            "file-manager.selection",
            "file-manager.currentFolder",
            "file-manager.activeAction"
          ],
          "apiActions": [
            "documentFolder.create",
            "document.rename",
            "document.move"
          ]
        },
        {
          "name": "delete_documents",
          "safety": "destructive",
          "description": "Delete the selected files or folders from the patient's document tree. Deleting a folder takes everything nested beneath it. Not reversible from this surface — read the selection first and confirm.",
          "descriptionKey": "ui.agent.patientFolder.workflows.deleteDocuments",
          "uiActions": [
            "file-manager.select_items",
            "file-manager.clear_selection"
          ],
          "stateReads": [
            "file-manager.selection",
            "file-manager.activeAction"
          ],
          "apiActions": [
            "document.delete"
          ]
        },
        {
          "name": "request_document_signature",
          "safety": "phi",
          "description": "Send one document out for the patient's signature. A pending document's Request signature row action opens the signature request modal with that document's signed versions table above the request form; for Via QR, the QR step follows in the same dialog (the full contract is signature-request.agent.ts). The banner's unsigned-documents count is the same signal, so read it to see what is already pending before requesting another. Puts a patient-identifiable document into an outbound signing envelope.",
          "descriptionKey": "ui.agent.patientFolder.workflows.requestDocumentSignature",
          "uiActions": [
            "file-manager.select_items",
            "dialog.close"
          ],
          "stateReads": [
            "file-manager.selection",
            "patient-summary-card.summary",
            "dialog.isOpen"
          ],
          "apiActions": [
            "signatureRequest.create"
          ]
        },
        {
          "name": "request_required_signatures",
          "safety": "phi",
          "description": "Ask the patient to sign every outstanding item in one request. The banner's Documents to sign button (a user-driven button with no adapter action) opens the signature request modal in required documents mode: the unsigned documents and anamnesis interviews, each with its own operator picker, one signer roster for the batch, and a link sent outcome after submit. A signer the host marks as under 18 shows a warning that never blocks the request. Read the banner's counts first to know what will be listed.",
          "descriptionKey": "ui.agent.patientFolder.workflows.requestRequiredSignatures",
          "uiActions": [
            "dialog.close",
            "dialog.dismiss"
          ],
          "stateReads": [
            "patient-summary-card.summary",
            "dialog.isOpen"
          ],
          "apiActions": [
            "signatureRequest.create"
          ]
        },
        {
          "name": "share_documents",
          "safety": "phi",
          "description": "Share the selected documents with the patient. The shared files then appear as a document-share bubble in the Communications thread. Sends patient-identifiable documents out of the practice.",
          "descriptionKey": "ui.agent.patientFolder.workflows.shareDocuments",
          "uiActions": [
            "file-manager.select_items"
          ],
          "stateReads": [
            "file-manager.selection"
          ],
          "apiActions": [
            "document.share"
          ]
        },
        {
          "name": "read_message_thread",
          "safety": "read",
          "description": "Read the per-patient message thread in the Communications tab — App, SMS, Email and inbound WhatsApp messages in one chronological log, with SMS delivery status and campaign / workflow / document-share provenance on each bubble — and scroll back to the latest message. Read-only.",
          "descriptionKey": "ui.agent.patientFolder.workflows.readMessageThread",
          "uiActions": [
            "chat-container.scroll_to_bottom"
          ],
          "apiActions": [
            "message.list"
          ]
        },
        {
          "name": "compose_message",
          "safety": "write",
          "description": "Draft a message to the patient: pick the outbound channel (App, SMS or Email — WhatsApp is inbound-only and never offered) and type the body. On SMS the composer counts GSM/Unicode segments including the appended practice sender name, so read the draft back before sending a long one. Nothing leaves the practice until the draft is submitted.",
          "descriptionKey": "ui.agent.patientFolder.workflows.composeMessage",
          "uiActions": [
            "select.set_value",
            "chat-input.set_value",
            "chat-input.focus"
          ],
          "stateReads": [
            "select.value",
            "chat-input.value",
            "chat-input.isEmpty"
          ],
          "apiActions": []
        },
        {
          "name": "send_message",
          "safety": "phi",
          "description": "Send the composed message to the patient over the picked channel and append it to the thread. The destination readout beside the channel picker names exactly where it lands — portal account, mobile number or email address — so confirm it before submitting. Sends patient-identifiable content out of the practice.",
          "descriptionKey": "ui.agent.patientFolder.workflows.sendMessage",
          "uiActions": [
            "chat-input.submit",
            "chat-input.clear"
          ],
          "stateReads": [
            "chat-input.value",
            "select.value"
          ],
          "apiActions": [
            "message.send"
          ]
        },
        {
          "name": "enable_patient_channel",
          "safety": "phi",
          "description": "Turn on a communication channel the patient has no route for yet — no portal account, no mobile number, no email address. The composer shows an enablement prompt in place of offering that channel; enabling it adds the channel back to the picker. Requires recording the patient contact detail the channel needs, so it writes patient-identifiable data.",
          "descriptionKey": "ui.agent.patientFolder.workflows.enablePatientChannel",
          "uiActions": [],
          "apiActions": [
            "patient.enableChannel"
          ]
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "patient-portal",
      "composes": [
        {
          "component": "social-sign-in-button",
          "as": "ssoSignIn"
        },
        {
          "component": "email-input",
          "as": "signInEmail"
        },
        {
          "component": "phone-input",
          "as": "signInPhone"
        },
        {
          "component": "otp-input",
          "as": "verifyCode"
        },
        {
          "component": "tab-bar",
          "as": "sectionNav"
        },
        {
          "component": "card",
          "as": "sectionCard"
        },
        {
          "component": "badge",
          "as": "appointmentBadge"
        },
        {
          "component": "dialog",
          "as": "cancelConfirm"
        },
        {
          "component": "button",
          "as": "cancelAppointment"
        },
        {
          "component": "alert",
          "as": "cancelTooLate"
        },
        {
          "component": "file-upload",
          "as": "documentUpload"
        },
        {
          "component": "progress",
          "as": "uploadProgress"
        },
        {
          "component": "form-field",
          "as": "detailsField"
        },
        {
          "component": "text-input",
          "as": "detailsName"
        },
        {
          "component": "fiscal-code-input",
          "as": "detailsFiscalCode"
        },
        {
          "component": "address-autocomplete",
          "as": "detailsAddress"
        },
        {
          "component": "date-picker",
          "as": "detailsBirthDate"
        },
        {
          "component": "select",
          "as": "detailsCountry"
        },
        {
          "component": "radio-group",
          "as": "detailsGender"
        },
        {
          "component": "separator",
          "as": "sectionDivider"
        }
      ],
      "workflows": [
        {
          "name": "sign_in_with_code",
          "safety": "write",
          "description": "Request a one-time SMS/email code, enter it, and authenticate into the portal.",
          "descriptionKey": "ui.agent.patientPortal.workflows.signInWithCode",
          "uiActions": [
            "otp-input.set_value"
          ],
          "stateReads": [
            "otp-input.isComplete",
            "email-input.value"
          ],
          "apiActions": [
            "auth.requestOtp",
            "auth.verifyOtp"
          ]
        },
        {
          "name": "navigate_section",
          "safety": "read",
          "description": "Switch between the Appointments, Documents, and My details portal sections.",
          "descriptionKey": "ui.agent.patientPortal.workflows.navigateSection",
          "uiActions": [],
          "apiActions": []
        },
        {
          "name": "check_in",
          "safety": "write",
          "description": "Start the day-of check-in for an upcoming appointment from the portal home.",
          "descriptionKey": "ui.agent.patientPortal.workflows.checkIn",
          "uiActions": [],
          "apiActions": [
            "appointment.checkIn"
          ]
        },
        {
          "name": "cancel_appointment",
          "safety": "destructive",
          "description": "Cancel an upcoming appointment after confirming in the dialog. Frees the slot.",
          "descriptionKey": "ui.agent.patientPortal.workflows.cancelAppointment",
          "uiActions": [
            "dialog.open",
            "dialog.close"
          ],
          "stateReads": [
            "dialog.isOpen"
          ],
          "apiActions": [
            "appointment.cancel"
          ]
        },
        {
          "name": "upload_document",
          "safety": "write",
          "description": "Upload a file (PDF/JPG/PNG) to the patient document library.",
          "descriptionKey": "ui.agent.patientPortal.workflows.uploadDocument",
          "uiActions": [
            "file-upload.clear"
          ],
          "stateReads": [
            "file-upload.files"
          ],
          "apiActions": [
            "document.upload"
          ]
        },
        {
          "name": "save_details",
          "safety": "write",
          "description": "Edit and save the patient personal details (contact, address, fiscal code).",
          "descriptionKey": "ui.agent.patientPortal.workflows.saveDetails",
          "uiActions": [
            "text-input.set_value",
            "fiscal-code-input.set_value",
            "address-autocomplete.set_value",
            "date-picker.set_date",
            "select.set_value",
            "radio-group.set_value"
          ],
          "stateReads": [
            "text-input.value",
            "fiscal-code-input.isValid",
            "address-autocomplete.value",
            "date-picker.value",
            "select.value",
            "radio-group.value"
          ],
          "apiActions": [
            "patient.updateDetails"
          ]
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "patient-record",
      "composes": [
        {
          "component": "control-room-rail",
          "as": "workspaceRail",
          "entity": "tool"
        },
        {
          "component": "patient-details",
          "as": "detailsPanel",
          "entity": "field"
        },
        {
          "component": "patient-summary-card",
          "as": "overviewCard"
        },
        {
          "component": "entity-summary",
          "as": "aiBrief"
        },
        {
          "component": "badge",
          "as": "alertCountChip"
        },
        {
          "component": "transaction-chip",
          "as": "balanceChip"
        },
        {
          "component": "link",
          "as": "contactLink"
        }
      ],
      "workflows": [
        {
          "name": "open_patient_tool",
          "safety": "read",
          "description": "Switch the Control Room rail between the patient tools — the editable \"Patient details\" panel and the AI summary — or collapse the rail back to its icon strip. View state only; no panel content is exposed.",
          "descriptionKey": "ui.agent.patientRecord.workflows.openPatientTool",
          "uiActions": [
            "control-room-rail.select_tool",
            "control-room-rail.open",
            "control-room-rail.close"
          ],
          "stateReads": [
            "control-room-rail.activeToolId"
          ],
          "apiActions": []
        },
        {
          "name": "read_record_status",
          "safety": "read",
          "description": "Read the structural state of the record already on screen — which patient the panel is bound to, which field keys are visible and in what order, and the card’s counts and flags (unpaid balance, unsigned documents, highlighted anamnesis answers, AI consent). Returns identifiers, counts and field KEYS only, never a field value.",
          "descriptionKey": "ui.agent.patientRecord.workflows.readRecordStatus",
          "uiActions": [],
          "stateReads": [
            "patient-details.patientId",
            "patient-details.visibleFieldOrder",
            "patient-summary-card.summary"
          ],
          "apiActions": []
        },
        {
          "name": "customize_field_set",
          "safety": "write",
          "description": "Show, hide and reorder the patient fields through the details panel’s cog picker. The one preference drives BOTH surfaces at once, so the main-area summary card reflects the change immediately. Mutates the per-user view preference, not the patient record, and is reversible with the same picker.",
          "descriptionKey": "ui.agent.patientRecord.workflows.customizeFieldSet",
          "uiActions": [
            "patient-details.set_visible_fields",
            "patient-details.set_field_order"
          ],
          "stateReads": [
            "patient-details.visibleFieldOrder"
          ],
          "apiActions": [
            "patientFieldPreference.save"
          ]
        },
        {
          "name": "update_patient_field",
          "safety": "phi",
          "description": "Write a patient field value from the details panel — an identity or contact field, or a clinical field such as the diagnosis note. Routes through the consumer’s audited save path, so the same permissions, validation and audit apply as to a human inline edit. Writes patient-identifiable data.",
          "descriptionKey": "ui.agent.patientRecord.workflows.updatePatientField",
          "uiActions": [
            "patient-details.update_field"
          ],
          "stateReads": [
            "patient-details.patientId"
          ],
          "apiActions": [
            "patient.updateField"
          ]
        },
        {
          "name": "copy_patient_identifier",
          "safety": "phi",
          "description": "Copy a sensitive identifier (e.g. the fiscal code) out of the details panel to the clipboard. The copy affordance lives inside the field row and exposes no adapter action, so this workflow documents the boundary rather than driving it: the value leaves the surface, so it is treated as a PHI egress and must be confirmed and audited.",
          "descriptionKey": "ui.agent.patientRecord.workflows.copyPatientIdentifier",
          "uiActions": [],
          "stateReads": [
            "patient-details.visibleFieldOrder"
          ],
          "apiActions": []
        },
        {
          "name": "refresh_ai_brief",
          "safety": "phi",
          "description": "Open the AI summary tool in the rail and request a fresh brief over this patient, then read back when it was generated and the shape of its sections (headings, tone, item counts — never the bullet text). Generation is gated upstream by the AI consent banner. Produces patient-identifiable clinical narrative, so it is stricter than EntitySummary’s own entity-agnostic write.",
          "descriptionKey": "ui.agent.patientRecord.workflows.refreshAiBrief",
          "uiActions": [
            "control-room-rail.select_tool",
            "entity-summary.regenerate"
          ],
          "stateReads": [
            "entity-summary.generatedAtIso",
            "entity-summary.sections",
            "control-room-rail.activeToolId"
          ],
          "apiActions": [
            "patientSummary.regenerate"
          ]
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "patients",
      "composes": [
        {
          "component": "data-table",
          "as": "roster",
          "entity": "patient"
        },
        {
          "component": "warning-stack",
          "as": "notices"
        },
        {
          "component": "button",
          "as": "bulkAction"
        },
        {
          "component": "icon-button-group",
          "as": "tableActions"
        }
      ],
      "workflows": [
        {
          "name": "filter_from_notice",
          "safety": "read",
          "description": "Apply a WarningStack notice’s \"View\" action to narrow the roster to the flagged patients (e.g. overdue balances, estimate-stage plans).",
          "descriptionKey": "ui.agent.patients.workflows.filterFromNotice",
          "uiActions": [
            "data-table.apply_filter"
          ],
          "stateReads": [
            "data-table.filter"
          ],
          "apiActions": []
        },
        {
          "name": "select_patients",
          "safety": "read",
          "description": "Select one or more patient rows in the roster for a bulk action.",
          "descriptionKey": "ui.agent.patients.workflows.selectPatients",
          "uiActions": [
            "data-table.select_rows",
            "data-table.get_selection"
          ],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": []
        },
        {
          "name": "send_reminders",
          "safety": "write",
          "description": "Send an appointment or balance reminder to the selected patients through their eligible channel (email or SMS).",
          "descriptionKey": "ui.agent.patients.workflows.sendReminders",
          "uiActions": [
            "data-table.get_selection"
          ],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": [
            "patient.sendReminder"
          ]
        },
        {
          "name": "tag_patients",
          "safety": "write",
          "description": "Add a tag to every selected patient.",
          "descriptionKey": "ui.agent.patients.workflows.tagPatients",
          "uiActions": [
            "data-table.get_selection"
          ],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": [
            "patient.tag"
          ]
        },
        {
          "name": "delete_patients",
          "safety": "destructive",
          "description": "Delete the selected patients. Archived patients cannot be deleted. Irreversible.",
          "descriptionKey": "ui.agent.patients.workflows.deletePatients",
          "uiActions": [
            "data-table.get_selection",
            "data-table.clear_selection"
          ],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": [
            "patient.delete"
          ]
        },
        {
          "name": "export_roster",
          "safety": "read",
          "description": "Export the current (optionally filtered) patient roster from the page-header table-tools cluster — CSV / Excel / PDF.",
          "descriptionKey": "ui.agent.patients.workflows.exportRoster",
          "uiActions": [],
          "apiActions": [
            "patient.export"
          ]
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "payment-automation-upsell",
      "composes": [
        {
          "component": "card",
          "as": "heroCard"
        },
        {
          "component": "benefit-card",
          "as": "howItWorks",
          "entity": "step"
        },
        {
          "component": "card",
          "as": "previewCard"
        },
        {
          "component": "list",
          "as": "previewList",
          "entity": "paymentRequest"
        },
        {
          "component": "badge",
          "as": "requestStatus"
        },
        {
          "component": "stat",
          "as": "proofMetric",
          "entity": "metric"
        },
        {
          "component": "card",
          "as": "featuresCard"
        },
        {
          "component": "list",
          "as": "featureList",
          "entity": "feature"
        },
        {
          "component": "button",
          "as": "activate"
        },
        {
          "component": "button",
          "as": "notifyAdmin"
        }
      ],
      "workflows": [
        {
          "name": "view_upsell",
          "safety": "read",
          "description": "Read the Payment Automation value preview: the how-it-works steps, the sample payment-request list, and the included-features checklist.",
          "descriptionKey": "ui.agent.paymentAutomationUpsell.workflows.viewUpsell",
          "uiActions": [],
          "apiActions": [
            "paymentAutomation.getModuleStatus"
          ]
        },
        {
          "name": "activate_module",
          "safety": "write",
          "description": "As the practice owner, activate the Payment Automation module on the subscription. Persists a billing change.",
          "descriptionKey": "ui.agent.paymentAutomationUpsell.workflows.activateModule",
          "uiActions": [],
          "apiActions": [
            "subscription.enableModule"
          ]
        },
        {
          "name": "notify_admin",
          "safety": "write",
          "description": "As a non-owner member, notify the practice owner / admin to activate the Payment Automation module.",
          "descriptionKey": "ui.agent.paymentAutomationUpsell.workflows.notifyAdmin",
          "uiActions": [],
          "apiActions": [
            "notification.notifyOwner"
          ]
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "periodontal-charting",
      "composes": [
        {
          "component": "card",
          "as": "chartCard"
        },
        {
          "component": "periodontal-chart",
          "as": "chart",
          "entity": "tooth"
        },
        {
          "component": "periodontal-risk-chart",
          "as": "riskProfile"
        },
        {
          "component": "periodontal-diagnosis",
          "as": "diagnosis"
        }
      ],
      "workflows": [
        {
          "name": "review_chart",
          "safety": "read",
          "description": "Read the exam back without changing it: the derived whole-mouth indices (mean probing depth, mean attachment level, plaque %, bleeding on probing %, scored-site and deep-pocket counts) and the narratable per-tooth problem list, ordered clinically with each tooth’s pockets deepest-first — e.g. “46: 8 mm disto-buccal pocket, bleeding, grade 2 mobility”. Structural readings and FDI ids only; the free-text per-tooth note is never returned.",
          "descriptionKey": "ui.agent.periodontalCharting.workflows.reviewChart",
          "uiActions": [
            "periodontal-chart.get_indices",
            "periodontal-chart.get_findings",
            "periodontal-chart.get_tooth"
          ],
          "stateReads": [
            "periodontal-chart.indices",
            "periodontal-chart.findings",
            "periodontal-chart.chartedTeeth",
            "periodontal-chart.missingTeeth"
          ],
          "apiActions": [
            "periodontalExam.get"
          ]
        },
        {
          "name": "record_probing_depths",
          "safety": "phi",
          "description": "Walk the mouth site by site during probing: move focus to a measurement input, then record the pocket depth and the gingival recession in whole millimetres at that site. Writes patient clinical data.",
          "descriptionKey": "ui.agent.periodontalCharting.workflows.recordProbingDepths",
          "uiActions": [
            "periodontal-chart.focus_site",
            "periodontal-chart.set_depth",
            "periodontal-chart.set_recession"
          ],
          "stateReads": [
            "periodontal-chart.indices"
          ],
          "apiActions": [
            "periodontalExam.updateSite"
          ]
        },
        {
          "name": "record_tooth_findings",
          "safety": "phi",
          "description": "Record the non-millimetre findings alongside the depths: bleeding on probing and plaque at a site, the tooth’s Miller mobility grade (0–3), and whether the tooth is present or absent. Writes patient clinical data.",
          "descriptionKey": "ui.agent.periodontalCharting.workflows.recordToothFindings",
          "uiActions": [
            "periodontal-chart.toggle_bleeding",
            "periodontal-chart.toggle_plaque",
            "periodontal-chart.set_mobility",
            "periodontal-chart.set_missing"
          ],
          "stateReads": [
            "periodontal-chart.findings",
            "periodontal-chart.missingTeeth"
          ],
          "apiActions": [
            "periodontalExam.updateTooth"
          ]
        },
        {
          "name": "read_risk_profile",
          "safety": "read",
          "description": "Read the Lang & Tonetti risk hexagon beside the chart: the overall periodontal risk verdict (low / moderate / high) and the per-factor bands (bleeding, pockets, tooth loss, bone loss vs age, smoking, systemic). Ordinal bands only — never the raw clinical inputs. The hexagon is display-only, so there is nothing to drive here.",
          "descriptionKey": "ui.agent.periodontalCharting.workflows.readRiskProfile",
          "uiActions": [],
          "stateReads": [
            "periodontal-risk-chart.overall",
            "periodontal-risk-chart.factorLevels"
          ],
          "apiActions": [
            "periodontalRisk.get"
          ]
        },
        {
          "name": "record_diagnosis",
          "safety": "phi",
          "description": "Record the 2017-classification diagnosis for the exam: stage (I–IV), grade (A–C), extent (localised / generalised / molar-incisor) and the ticked contributing factors, then read back the composed diagnosis sentence and whether the form is complete. Writes patient clinical data; the clinician’s free-text note is never exposed.",
          "descriptionKey": "ui.agent.periodontalCharting.workflows.recordDiagnosis",
          "uiActions": [
            "periodontal-diagnosis.set_stage",
            "periodontal-diagnosis.set_grade",
            "periodontal-diagnosis.set_extent",
            "periodontal-diagnosis.toggle_factor",
            "periodontal-diagnosis.get_diagnosis"
          ],
          "stateReads": [
            "periodontal-diagnosis.diagnosis",
            "periodontal-diagnosis.summary",
            "periodontal-diagnosis.complete"
          ],
          "apiActions": [
            "periodontalDiagnosis.update"
          ]
        },
        {
          "name": "save_exam",
          "safety": "phi",
          "description": "Persist the whole periodontal examination — every probing reading plus the recorded diagnosis — against the patient record once charting is finished. Writes patient clinical data.",
          "descriptionKey": "ui.agent.periodontalCharting.workflows.saveExam",
          "uiActions": [],
          "stateReads": [
            "periodontal-chart.indices",
            "periodontal-chart.chartedTeeth",
            "periodontal-diagnosis.complete"
          ],
          "apiActions": [
            "periodontalExam.save"
          ]
        },
        {
          "name": "clear_tooth_readings",
          "safety": "destructive",
          "description": "Discard every reading captured on one mischarted tooth — all six sites, the mobility grade and the missing / implant flags. Not undoable from this surface; confirm the FDI id with the clinician first.",
          "descriptionKey": "ui.agent.periodontalCharting.workflows.clearToothReadings",
          "uiActions": [
            "periodontal-chart.clear_tooth"
          ],
          "stateReads": [
            "periodontal-chart.chartedTeeth"
          ],
          "apiActions": [
            "periodontalExam.clearTooth"
          ]
        },
        {
          "name": "clear_diagnosis",
          "safety": "destructive",
          "description": "Reset the recorded stage, grade, extent and contributing factors back to empty, leaving the chart readings untouched. Not undoable from this surface.",
          "descriptionKey": "ui.agent.periodontalCharting.workflows.clearDiagnosis",
          "uiActions": [
            "periodontal-diagnosis.clear_diagnosis"
          ],
          "stateReads": [
            "periodontal-diagnosis.complete"
          ],
          "apiActions": [
            "periodontalDiagnosis.clear"
          ]
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "prenota",
      "composes": [
        {
          "component": "public-header",
          "as": "header"
        },
        {
          "component": "public-footer",
          "as": "footer"
        },
        {
          "component": "logo",
          "as": "brandmark"
        },
        {
          "component": "combobox",
          "as": "specialtySearch"
        },
        {
          "component": "combobox",
          "as": "locationSearch"
        },
        {
          "component": "button",
          "as": "searchCta"
        },
        {
          "component": "practice-results",
          "as": "results",
          "entity": "practice"
        },
        {
          "component": "reviews-panel",
          "as": "reviews",
          "entity": "review"
        },
        {
          "component": "contact-profile-card",
          "as": "contact"
        },
        {
          "component": "operator-hero",
          "as": "operatorHero"
        },
        {
          "component": "rating",
          "as": "score"
        },
        {
          "component": "benefit-card",
          "as": "benefit"
        },
        {
          "component": "stat",
          "as": "trustStat",
          "entity": "metric"
        },
        {
          "component": "card",
          "as": "heroCard"
        },
        {
          "component": "badge",
          "as": "heroEyebrow"
        },
        {
          "component": "tag",
          "as": "filterChip"
        },
        {
          "component": "avatar",
          "as": "practiceAvatar"
        },
        {
          "component": "booking",
          "as": "bookingFlow"
        },
        {
          "component": "combobox",
          "as": "servicePicker",
          "entity": "service"
        },
        {
          "component": "multi-select",
          "as": "operatorPicker",
          "entity": "operator"
        },
        {
          "component": "slot-grid",
          "as": "slotPicker",
          "entity": "slot"
        },
        {
          "component": "form-field",
          "as": "detailsField"
        },
        {
          "component": "text-input",
          "as": "patientName"
        },
        {
          "component": "email-input",
          "as": "patientEmail"
        },
        {
          "component": "phone-input",
          "as": "patientMobile"
        },
        {
          "component": "date-picker",
          "as": "dateOfBirth"
        },
        {
          "component": "text-area",
          "as": "bookingNote"
        },
        {
          "component": "checkbox-group",
          "as": "consents"
        },
        {
          "component": "alert",
          "as": "bookingOutcome"
        },
        {
          "component": "spinner",
          "as": "confirmSpinner"
        },
        {
          "component": "live-region",
          "as": "confirmStatus"
        }
      ],
      "workflows": [
        {
          "name": "search_practitioners",
          "safety": "read",
          "description": "Pick a specialty / clinic and a location in the hero search comboboxes and submit to find matching practitioners.",
          "descriptionKey": "ui.agent.prenota.workflows.searchPractitioners",
          "uiActions": [
            "combobox.set_value",
            "combobox.apply_filter"
          ],
          "stateReads": [
            "combobox.value",
            "combobox.query"
          ],
          "apiActions": [
            "practice.search"
          ]
        },
        {
          "name": "browse_results",
          "safety": "read",
          "description": "Scroll the search results list and focus a map pin to locate a practice geographically.",
          "descriptionKey": "ui.agent.prenota.workflows.browseResults",
          "uiActions": [
            "practice-results.scroll_to_result",
            "practice-results.focus_pin"
          ],
          "stateReads": [
            "practice-results.variant"
          ],
          "apiActions": [
            "practice.list"
          ]
        },
        {
          "name": "open_practice",
          "safety": "read",
          "description": "Open a practice or operator profile from a result card to view contact details and reviews.",
          "descriptionKey": "ui.agent.prenota.workflows.openPractice",
          "uiActions": [
            "practice-results.scroll_to_result"
          ],
          "apiActions": [
            "practice.get"
          ]
        },
        {
          "name": "filter_reviews",
          "safety": "read",
          "description": "Filter the reviews panel on a profile by star rating to read targeted feedback.",
          "descriptionKey": "ui.agent.prenota.workflows.filterReviews",
          "uiActions": [
            "reviews-panel.set_filter"
          ],
          "stateReads": [
            "reviews-panel.filter",
            "reviews-panel.visibleCount"
          ],
          "apiActions": [
            "review.list"
          ]
        },
        {
          "name": "book_visit",
          "safety": "write",
          "description": "Start booking a visit from a result card next-available slot or a profile \"Book visit\" CTA.",
          "descriptionKey": "ui.agent.prenota.workflows.bookVisit",
          "uiActions": [],
          "apiActions": [
            "appointment.book"
          ]
        },
        {
          "name": "navigate_menu",
          "safety": "read",
          "description": "Open the public header navigation (doctors, pricing, for-practices) or the sign-in / register actions.",
          "descriptionKey": "ui.agent.prenota.workflows.navigateMenu",
          "uiActions": [
            "public-header.open_menu",
            "public-header.close_menu"
          ],
          "stateReads": [
            "public-header.menuOpen"
          ],
          "apiActions": [
            "navigation.go"
          ]
        },
        {
          "name": "choose_service",
          "safety": "write",
          "description": "Choose the service to book on the booking page. Type into the service combobox to narrow the practice catalogue, commit the matching service id, then move the flow on. Reading `combobox.query` back confirms what was actually typed; `combobox.value` confirms what stuck. This is the step patients abandon most, so prefer setting the service id directly over leaving a half-typed filter.",
          "descriptionKey": "ui.agent.prenota.workflows.chooseService",
          "uiActions": [
            "combobox.apply_filter",
            "combobox.set_value",
            "booking.goto_step"
          ],
          "stateReads": [
            "combobox.query",
            "combobox.value",
            "booking.variant"
          ],
          "apiActions": [
            "service.list"
          ]
        },
        {
          "name": "choose_operator",
          "safety": "write",
          "description": "Narrow the booking to particular practitioners using the operator multi-select, or clear it back to \"no preference\". An empty selection means any operator — clearing is the correct way to widen availability, not a failure.",
          "descriptionKey": "ui.agent.prenota.workflows.chooseOperator",
          "uiActions": [
            "multi-select.apply_filter",
            "multi-select.set_selection",
            "multi-select.clear_selection"
          ],
          "stateReads": [
            "multi-select.selection",
            "multi-select.query"
          ],
          "apiActions": [
            "operator.list"
          ]
        },
        {
          "name": "pick_slot",
          "safety": "write",
          "description": "Find and select an appointment slot in the four-day grid. Read `status` before concluding there is no availability — `loading` means the window has not resolved. Read `slotsByDay` for the bookable ids in view (it already includes slots collapsed behind \"Show more\", so they can be selected without expanding), page with `next_days` / `previous_days` while `hasNext` / `hasPrevious` allow it, then commit with `select_slot`. Selecting a slot only fills the booking draft — it does not book anything.",
          "descriptionKey": "ui.agent.prenota.workflows.pickSlot",
          "uiActions": [
            "slot-grid.previous_days",
            "slot-grid.next_days",
            "slot-grid.select_slot"
          ],
          "stateReads": [
            "slot-grid.status",
            "slot-grid.visibleDays",
            "slot-grid.slotsByDay",
            "slot-grid.hasPrevious",
            "slot-grid.hasNext",
            "slot-grid.selectedSlotId"
          ],
          "apiActions": [
            "availability.search"
          ]
        },
        {
          "name": "submit_booking_request",
          "safety": "phi",
          "description": "Commit the booking request once a service, slot and patient details are in place. The commit goes through the appointment tool layer, not the form: the details fields (name, email, mobile, optional date of birth and fiscal code, consents) have no adapter and are not addressable through the registry, so send the payload to `appointment.book` rather than trying to type into the form. `goto_step` is only for walking the patient back to a step they left incomplete.",
          "descriptionKey": "ui.agent.prenota.workflows.submitBookingRequest",
          "uiActions": [
            "booking.goto_step"
          ],
          "stateReads": [
            "booking.variant"
          ],
          "apiActions": [
            "appointment.book"
          ]
        },
        {
          "name": "confirm_booking_request",
          "safety": "write",
          "description": "Confirm a pending booking request from the single-use link the patient is emailed (`/conferma?token=…`). The landing page confirms on load and only reports the outcome, so there is no UI to drive — redeem the token through the API. A token is single-use: a second attempt reports \"expired\", which is the correct terminal state, not an error to retry.",
          "descriptionKey": "ui.agent.prenota.workflows.confirmBookingRequest",
          "uiActions": [],
          "apiActions": [
            "bookingRequest.confirm"
          ]
        },
        {
          "name": "abandon_booking",
          "safety": "destructive",
          "description": "Clear an in-progress booking back to an empty flow. Destructive: everything the patient has entered — service, operator, slot and any details already typed — is lost and cannot be recovered from the UI. Confirm with the patient first.",
          "descriptionKey": "ui.agent.prenota.workflows.abandonBooking",
          "uiActions": [
            "booking.reset"
          ],
          "stateReads": [
            "booking.variant"
          ],
          "apiActions": []
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "registration-form",
      "composes": [
        {
          "component": "card",
          "as": "card"
        },
        {
          "component": "alert",
          "as": "formError"
        },
        {
          "component": "error-summary",
          "as": "errorSummary"
        },
        {
          "component": "form-field",
          "as": "field"
        },
        {
          "component": "text-input",
          "as": "firstName"
        },
        {
          "component": "text-input",
          "as": "lastName"
        },
        {
          "component": "email-input",
          "as": "email"
        },
        {
          "component": "email-input",
          "as": "emailConfirm"
        },
        {
          "component": "password-input",
          "as": "password"
        },
        {
          "component": "password-input",
          "as": "passwordConfirm"
        },
        {
          "component": "phone-input",
          "as": "phone"
        },
        {
          "component": "otp-input",
          "as": "emailCode"
        },
        {
          "component": "otp-input",
          "as": "phoneCode"
        },
        {
          "component": "select",
          "as": "branch"
        },
        {
          "component": "checkbox",
          "as": "terms"
        },
        {
          "component": "recaptcha-widget",
          "as": "captcha"
        },
        {
          "component": "button",
          "as": "submit"
        },
        {
          "component": "dev-bypass-button",
          "as": "devBypass"
        }
      ],
      "workflows": [
        {
          "name": "read_form",
          "safety": "read",
          "description": "Read which fields the form asks for and which have a problem. The host picks the fields, so read them from the page: each one that shows sits in a wrapper with `data-field`. A field with a problem has `aria-invalid=\"true\"` on its control and its message in a `data-slot=\"error\"` element inside the wrapper. After a refused submit the fields with a problem are also listed in `data-component=\"error-summary\"` at the top of the form, one item per field (`data-error-field`). A message about the whole form is in `data-field=\"form\"`. An email the person cannot change is marked `readonly`. When the host asks for a code, a field's wrapper also carries `data-verification` (`idle`, `sent` or `verified`); a verified field is `readonly`. When the address already has an account, the email message says so and the two link-buttons under it lead on: sign in (`data-action=\"sign-in\"`) or reset the password (`data-action=\"reset-password\"`). Never read or repeat the password fields.",
          "descriptionKey": "ui.agent.registrationForm.workflows.readForm",
          "uiActions": [],
          "apiActions": []
        },
        {
          "name": "register",
          "safety": "write",
          "description": "Create the account (`data-action=\"submit\"`). The person fills in the fields and accepts the terms themselves; the form does not submit until every field is valid and, when the host asks for codes, until the email and the phone are verified; it lists what is wrong in its error summary and moves focus there. The host then registers the account: through its `onSubmit` handler, or as a native form post to its own field names.",
          "descriptionKey": "ui.agent.registrationForm.workflows.register",
          "uiActions": [],
          "apiActions": [
            "account.register"
          ]
        },
        {
          "name": "verify_contact",
          "safety": "write",
          "description": "Prove an email or a phone number with a code, when the host asks for it (a field wrapper has `data-verification`). Press Send code (`data-action=\"send-code\"`) beside the field; the code goes to the person's own inbox or phone, so the person reads it and types it into the code box (`data-component=\"otp-input\"`), or presses Verify (`data-action=\"verify-code\"`). Send a new code is `data-action=\"resend-code\"` and waits a few seconds; `data-action=\"change-value\"` returns to editing. Never read or guess the code. When it is right the field becomes `readonly` and `data-verification` is `verified`. The host's server holds the verified value and checks it again on submit.",
          "descriptionKey": "ui.agent.registrationForm.workflows.verifyContact",
          "uiActions": [],
          "apiActions": [
            "account.verify_contact"
          ]
        },
        {
          "name": "dev_bypass",
          "safety": "write",
          "description": "Development only: press the shortcut (`data-component=\"dev-bypass-button\"`). It puts the values the host supplied into the fields that show, as if typed, and submits the form through the normal path when the host asked for that; a host may instead run a handler of its own, such as a development-only route. The kit holds no test data. The button is present only when the host's server reports a development environment, and what it submits is checked by the server like any other submit.",
          "descriptionKey": "ui.agent.registrationForm.workflows.devBypass",
          "uiActions": [],
          "apiActions": []
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "reset-password-form",
      "composes": [
        {
          "component": "card",
          "as": "card"
        },
        {
          "component": "alert",
          "as": "formError"
        },
        {
          "component": "error-summary",
          "as": "errorSummary"
        },
        {
          "component": "alert",
          "as": "result"
        },
        {
          "component": "form-field",
          "as": "field"
        },
        {
          "component": "email-input",
          "as": "email"
        },
        {
          "component": "password-input",
          "as": "password"
        },
        {
          "component": "button",
          "as": "submit"
        }
      ],
      "workflows": [
        {
          "name": "read_form",
          "safety": "read",
          "description": "Read where the reset stands. The root carries `data-state`: `form` while the passwords are asked for, `done` once the password has changed, `expired` when the link no longer works. The result (`data-slot=\"result\"`) replaces the form. In the form, the address the password is for may show read-only in `data-field=\"email\"`; the new password is in `data-field=\"password\"` with its rules checklist, and its repeat in `data-field=\"passwordConfirm\"`. A field with a problem carries `aria-invalid=\"true\"` on its control and its message in a `data-slot=\"error\"` element, also listed in `data-component=\"error-summary\"` after a refused submit; a message about the whole form is in `data-field=\"form\"`.",
          "descriptionKey": "ui.agent.resetPasswordForm.workflows.readForm",
          "uiActions": [],
          "apiActions": []
        },
        {
          "name": "change_password",
          "safety": "write",
          "description": "Choose a new password (`data-action=\"submit\"`). The person types both passwords themselves; an agent never types or reads a password. The form does not submit until the password meets every rule and the two entries match. The host then changes the password, through its `onSubmit` handler or a native form post, and shows the `done` state.",
          "descriptionKey": "ui.agent.resetPasswordForm.workflows.changePassword",
          "uiActions": [],
          "apiActions": [
            "auth.resetPassword"
          ]
        },
        {
          "name": "sign_in",
          "safety": "read",
          "description": "Go to the sign-in page once the password has changed (`data-action=\"login\"`). Present only in the `done` state, and when the host gives its address.",
          "descriptionKey": "ui.agent.resetPasswordForm.workflows.signIn",
          "uiActions": [],
          "apiActions": []
        },
        {
          "name": "request_new_link",
          "safety": "read",
          "description": "Go to the page that asks for a new reset link (`data-action=\"request-link\"`). Present only in the `expired` state, and when the host gives its address.",
          "descriptionKey": "ui.agent.resetPasswordForm.workflows.requestNewLink",
          "uiActions": [],
          "apiActions": []
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "roi-dashboard",
      "composes": [
        {
          "component": "app-frame",
          "as": "frame"
        },
        {
          "component": "header",
          "as": "topBar"
        },
        {
          "component": "sidebar",
          "as": "mainNav"
        },
        {
          "component": "tool-rail",
          "as": "inboxRail",
          "entity": "notification"
        },
        {
          "component": "tabs",
          "as": "roleSwitcher"
        },
        {
          "component": "card",
          "as": "cubotto",
          "entity": "stage"
        },
        {
          "component": "chart",
          "as": "kpiChart"
        },
        {
          "component": "sparkline",
          "as": "kpiSparkline"
        },
        {
          "component": "stat",
          "as": "kpiStat"
        },
        {
          "component": "badge",
          "as": "efficiencyChip"
        },
        {
          "component": "warning-stack",
          "as": "alertsStrip",
          "entity": "alert"
        },
        {
          "component": "button",
          "as": "alertAction"
        },
        {
          "component": "empty-state",
          "as": "noAlertsState"
        }
      ],
      "workflows": [
        {
          "name": "view_funnel",
          "safety": "read",
          "description": "Read the patient-journey funnel — per-stage efficiency, time saved, and potential for the selected period.",
          "descriptionKey": "ui.agent.roiDashboard.workflows.viewFunnel",
          "uiActions": [],
          "apiActions": [
            "roi.getFunnel"
          ]
        },
        {
          "name": "set_period",
          "safety": "read",
          "description": "Change the reporting period for the whole funnel; every cubotto and KPI recomputes.",
          "descriptionKey": "ui.agent.roiDashboard.workflows.setPeriod",
          "uiActions": [],
          "apiActions": [
            "roi.setPeriod"
          ]
        },
        {
          "name": "drill_into_stage",
          "safety": "read",
          "description": "Open a stage cubotto to its per-KPI drill-down breakdown (and the AI insight cubotto to the ROI overview).",
          "descriptionKey": "ui.agent.roiDashboard.workflows.drillIntoStage",
          "uiActions": [],
          "apiActions": [
            "roi.getStageBreakdown"
          ]
        },
        {
          "name": "switch_role",
          "safety": "read",
          "description": "Switch the dashboard to another role via the multi-role tab switcher and read the active role.",
          "descriptionKey": "ui.agent.roiDashboard.workflows.switchRole",
          "uiActions": [
            "tabs.select_tab"
          ],
          "stateReads": [
            "tabs.activeTab"
          ],
          "apiActions": []
        },
        {
          "name": "open_inbox",
          "safety": "read",
          "description": "Open the inbox rail's notifications/messages tool and read which tool is active.",
          "descriptionKey": "ui.agent.roiDashboard.workflows.openInbox",
          "uiActions": [
            "tool-rail.open"
          ],
          "stateReads": [
            "tool-rail.activeToolId"
          ],
          "apiActions": []
        },
        {
          "name": "export_kpi",
          "safety": "read",
          "description": "Export a KPI chart as a PNG for a report, or request a full ROI report export.",
          "descriptionKey": "ui.agent.roiDashboard.workflows.exportKpi",
          "uiActions": [
            "chart.export_png",
            "sparkline.export_png"
          ],
          "apiActions": [
            "roi.exportReport"
          ]
        },
        {
          "name": "dismiss_alert",
          "safety": "write",
          "description": "Dismiss an item from the top-of-page alerts strip. Persists the dismissal so it stays hidden.",
          "descriptionKey": "ui.agent.roiDashboard.workflows.dismissAlert",
          "uiActions": [],
          "apiActions": [
            "alert.dismiss"
          ]
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "send-registration-link-form",
      "composes": [
        {
          "component": "card",
          "as": "card"
        },
        {
          "component": "alert",
          "as": "notice"
        },
        {
          "component": "error-summary",
          "as": "errorSummary"
        },
        {
          "component": "form-field",
          "as": "field"
        },
        {
          "component": "email-input",
          "as": "email"
        },
        {
          "component": "email-input",
          "as": "emailConfirm"
        },
        {
          "component": "phone-input",
          "as": "phone"
        },
        {
          "component": "phone-input",
          "as": "phoneConfirm"
        },
        {
          "component": "date-picker",
          "as": "allowLoginUntil"
        },
        {
          "component": "button",
          "as": "submit"
        }
      ],
      "workflows": [
        {
          "name": "read_form",
          "safety": "read",
          "description": "Read which fields have a problem. Each field sits in a wrapper with `data-field`; a field with a problem has `aria-invalid=\"true\"` on its control and its message in a `data-slot=\"error\"` element. After a refused submit the fields with a problem are listed in `data-component=\"error-summary\"`. After a send the root has `data-state=\"sent\"` and the result is in `data-slot=\"sent\"`.",
          "descriptionKey": "ui.agent.sendRegistrationLinkForm.workflows.readForm",
          "uiActions": [],
          "apiActions": []
        },
        {
          "name": "send_link",
          "safety": "write",
          "description": "Send the registration link (`data-action=\"submit\"`). The person fills in the email twice, a mobile phone twice and the last day login is allowed; the form does not submit until every field is valid. The host then sends the email through a native form post or its `onSubmit` handler.",
          "descriptionKey": "ui.agent.sendRegistrationLinkForm.workflows.sendLink",
          "uiActions": [],
          "apiActions": [
            "doctor.sendRegistrationLink"
          ]
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "services",
      "composes": [
        {
          "component": "data-table",
          "as": "catalogue",
          "entity": "service"
        },
        {
          "component": "card",
          "as": "gridShell"
        },
        {
          "component": "icon-button-group",
          "as": "tableActions"
        },
        {
          "component": "icon-button",
          "as": "tableAction"
        },
        {
          "component": "switch",
          "as": "compactActionsToggle"
        }
      ],
      "workflows": [
        {
          "name": "filter_services",
          "safety": "read",
          "description": "Narrow the catalogue by name, code, category, VAT rate or active status using the per-column filters.",
          "descriptionKey": "ui.agent.services.workflows.filterServices",
          "uiActions": [
            "data-table.apply_filter"
          ],
          "stateReads": [
            "data-table.filter"
          ],
          "apiActions": [
            "service.list"
          ]
        },
        {
          "name": "sort_catalogue",
          "safety": "read",
          "description": "Re-sort the catalogue by any column (e.g. price, duration, active).",
          "descriptionKey": "ui.agent.services.workflows.sortCatalogue",
          "uiActions": [
            "data-table.sort_by"
          ],
          "stateReads": [
            "data-table.sort"
          ],
          "apiActions": []
        },
        {
          "name": "compact_actions",
          "safety": "read",
          "description": "Toggle the ColumnToggle settings-footer switch to compact the per-row action column.",
          "descriptionKey": "ui.agent.services.workflows.compactActions",
          "uiActions": [
            "switch.set_checked"
          ],
          "stateReads": [
            "switch.checked"
          ],
          "apiActions": []
        },
        {
          "name": "toggle_active",
          "safety": "write",
          "description": "Flip a service’s availability via its per-row Active toggle so it is offered (or withdrawn) on new plans.",
          "descriptionKey": "ui.agent.services.workflows.toggleActive",
          "uiActions": [
            "data-table.get_selection"
          ],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": [
            "service.setActive"
          ]
        },
        {
          "name": "export_catalogue",
          "safety": "read",
          "description": "Export the current (optionally filtered) catalogue from the page-header table-tools cluster — CSV / Excel / PDF.",
          "descriptionKey": "ui.agent.services.workflows.exportCatalogue",
          "uiActions": [],
          "apiActions": [
            "service.export"
          ]
        },
        {
          "name": "edit_service",
          "safety": "write",
          "description": "Edit the selected service (e.g. price, duration, VAT) from its row action.",
          "descriptionKey": "ui.agent.services.workflows.editService",
          "uiActions": [
            "data-table.get_selection"
          ],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": [
            "service.update"
          ]
        },
        {
          "name": "duplicate_service",
          "safety": "write",
          "description": "Duplicate the selected service into a new editable copy from its row action.",
          "descriptionKey": "ui.agent.services.workflows.duplicateService",
          "uiActions": [
            "data-table.get_selection"
          ],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": [
            "service.duplicate"
          ]
        },
        {
          "name": "delete_service",
          "safety": "destructive",
          "description": "Delete the selected service from its row action. A service in use on a plan cannot be deleted. Irreversible.",
          "descriptionKey": "ui.agent.services.workflows.deleteService",
          "uiActions": [
            "data-table.get_selection",
            "data-table.clear_selection"
          ],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": [
            "service.delete"
          ]
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "settings",
      "composes": [
        {
          "component": "app-frame",
          "as": "shell"
        },
        {
          "component": "header",
          "as": "banner"
        },
        {
          "component": "sidebar",
          "as": "primaryNav"
        },
        {
          "component": "control-room-rail",
          "as": "toolRail"
        },
        {
          "component": "data-table",
          "as": "sectionList",
          "entity": "settingsRecord"
        },
        {
          "component": "dialog",
          "as": "recordDialog"
        },
        {
          "component": "form-field",
          "as": "field"
        },
        {
          "component": "text-input",
          "as": "textField"
        },
        {
          "component": "iban-input",
          "as": "ibanField"
        },
        {
          "component": "permission-matrix",
          "as": "permissions"
        },
        {
          "component": "connection-status",
          "as": "paymentConnection"
        },
        {
          "component": "image-cropper",
          "as": "photoCropper"
        },
        {
          "component": "switch",
          "as": "toggle"
        },
        {
          "component": "select",
          "as": "choice"
        },
        {
          "component": "radio-group",
          "as": "optionGroup"
        },
        {
          "component": "checkbox-group",
          "as": "multiChoice"
        },
        {
          "component": "color-picker",
          "as": "colour"
        },
        {
          "component": "file-upload",
          "as": "imageUpload"
        },
        {
          "component": "copy-field",
          "as": "secret"
        },
        {
          "component": "button",
          "as": "save"
        }
      ],
      "workflows": [
        {
          "name": "open_section",
          "safety": "read",
          "description": "Open a settings section from the Hub or the grouped section nav. Read-only navigation.",
          "descriptionKey": "ui.agent.settings.workflows.openSection",
          "uiActions": [],
          "apiActions": []
        },
        {
          "name": "edit_text_setting",
          "safety": "write",
          "description": "Set a text field in the active section (e.g. practice name, booking address, bank IBAN); marks the form dirty and enables Save.",
          "descriptionKey": "ui.agent.settings.workflows.editTextSetting",
          "uiActions": [
            "text-input.set_value",
            "text-input.clear",
            "iban-input.set_value"
          ],
          "stateReads": [
            "text-input.value",
            "iban-input.value"
          ],
          "apiActions": []
        },
        {
          "name": "toggle_setting",
          "safety": "write",
          "description": "Turn a boolean setting on or off (e.g. yearly numbering, group services).",
          "descriptionKey": "ui.agent.settings.workflows.toggleSetting",
          "uiActions": [
            "switch.set_checked",
            "switch.toggle"
          ],
          "stateReads": [
            "switch.checked"
          ],
          "apiActions": []
        },
        {
          "name": "choose_option",
          "safety": "write",
          "description": "Pick a single option from a select or radio group (e.g. tax regime, document type, stamp method).",
          "descriptionKey": "ui.agent.settings.workflows.chooseOption",
          "uiActions": [
            "select.set_value",
            "select.open",
            "select.close",
            "radio-group.set_value"
          ],
          "stateReads": [
            "select.value",
            "radio-group.value"
          ],
          "apiActions": []
        },
        {
          "name": "set_multi_choice",
          "safety": "write",
          "description": "Select or clear members of a multi-choice group (e.g. accepted insurers, active branches, per-area permissions).",
          "descriptionKey": "ui.agent.settings.workflows.setMultiChoice",
          "uiActions": [
            "checkbox-group.set_selection",
            "checkbox-group.clear_selection",
            "permission-matrix.set_selection",
            "permission-matrix.clear"
          ],
          "stateReads": [
            "checkbox-group.selection",
            "permission-matrix.selection"
          ],
          "apiActions": []
        },
        {
          "name": "pick_colour",
          "safety": "write",
          "description": "Choose a colour from the practice palette (e.g. booking page accent).",
          "descriptionKey": "ui.agent.settings.workflows.pickColour",
          "uiActions": [
            "color-picker.set_value"
          ],
          "stateReads": [
            "color-picker.value"
          ],
          "apiActions": []
        },
        {
          "name": "save_section",
          "safety": "write",
          "description": "Persist the dirty section form. Save is disabled until a field changes.",
          "descriptionKey": "ui.agent.settings.workflows.saveSection",
          "uiActions": [],
          "apiActions": [
            "settings.updateSection"
          ]
        },
        {
          "name": "add_record",
          "safety": "write",
          "description": "Open the create dialog for a list section (cash & banks, chairs, payment types…) and persist a new record.",
          "descriptionKey": "ui.agent.settings.workflows.addRecord",
          "uiActions": [
            "dialog.open",
            "text-input.set_value",
            "dialog.close"
          ],
          "apiActions": [
            "settings.createRecord"
          ]
        },
        {
          "name": "delete_record",
          "safety": "destructive",
          "description": "Remove a record from a list section after confirmation. Irreversible.",
          "descriptionKey": "ui.agent.settings.workflows.deleteRecord",
          "uiActions": [
            "data-table.clear_selection"
          ],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": [
            "settings.deleteRecord"
          ]
        },
        {
          "name": "filter_records",
          "safety": "read",
          "description": "Filter the rows of a list section by a column value.",
          "descriptionKey": "ui.agent.settings.workflows.filterRecords",
          "uiActions": [
            "data-table.apply_filter"
          ],
          "stateReads": [
            "data-table.filter"
          ],
          "apiActions": []
        },
        {
          "name": "upload_practice_photo",
          "safety": "write",
          "description": "Upload, crop, or remove the practice / profile photo.",
          "descriptionKey": "ui.agent.settings.workflows.uploadPracticePhoto",
          "uiActions": [
            "file-upload.remove_file",
            "file-upload.clear",
            "image-cropper.set_crop"
          ],
          "stateReads": [
            "file-upload.files",
            "image-cropper.crop"
          ],
          "apiActions": [
            "settings.uploadImage"
          ]
        },
        {
          "name": "copy_secret",
          "safety": "read",
          "description": "Copy a read-only secret to the clipboard (API key, data-import key, support PIN, iCal feed URL).",
          "descriptionKey": "ui.agent.settings.workflows.copySecret",
          "uiActions": [
            "copy-field.copy"
          ],
          "stateReads": [
            "copy-field.value"
          ],
          "apiActions": []
        },
        {
          "name": "revoke_api_key",
          "safety": "destructive",
          "description": "Revoke or regenerate an API key. Apps using the old key lose access immediately.",
          "descriptionKey": "ui.agent.settings.workflows.revokeApiKey",
          "uiActions": [],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": [
            "apiKey.revoke",
            "apiKey.regenerate"
          ]
        },
        {
          "name": "connect_online_payments",
          "safety": "write",
          "description": "Connect or disconnect the Stripe account used for online payments.",
          "descriptionKey": "ui.agent.settings.workflows.connectOnlinePayments",
          "uiActions": [
            "connection-status.connect",
            "connection-status.disconnect"
          ],
          "stateReads": [
            "connection-status.status"
          ],
          "apiActions": [
            "onlinePayment.connectStripe",
            "onlinePayment.disconnectStripe"
          ]
        },
        {
          "name": "delete_archive",
          "safety": "destructive",
          "description": "Delete the current archive after a password-gated confirmation. Permanently removes all of its data. Irreversible.",
          "descriptionKey": "ui.agent.settings.workflows.deleteArchive",
          "uiActions": [
            "dialog.open",
            "text-input.set_value"
          ],
          "apiActions": [
            "archive.delete"
          ]
        },
        {
          "name": "open_tool",
          "safety": "read",
          "description": "Open or switch a Control-Room rail tool (inbox, Alia) without leaving Settings.",
          "descriptionKey": "ui.agent.settings.workflows.openTool",
          "uiActions": [
            "control-room-rail.open",
            "control-room-rail.select_tool",
            "control-room-rail.close"
          ],
          "apiActions": []
        },
        {
          "name": "collapse_sidebar",
          "safety": "read",
          "description": "Collapse or expand the primary navigation sidebar.",
          "descriptionKey": "ui.agent.settings.workflows.collapseSidebar",
          "uiActions": [
            "sidebar.toggle_collapsed"
          ],
          "apiActions": []
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "signature-request",
      "composes": [
        {
          "component": "dialog",
          "as": "requestModal"
        },
        {
          "component": "skeleton",
          "as": "signaturesLoading"
        },
        {
          "component": "skeleton",
          "as": "formLoading"
        },
        {
          "component": "signature-status-chip",
          "as": "signatureStatus",
          "entity": "signature"
        },
        {
          "component": "tooltip",
          "as": "signerBreakdown",
          "entity": "signature"
        },
        {
          "component": "icon-button",
          "as": "viewSignature",
          "entity": "signature"
        },
        {
          "component": "icon-button",
          "as": "downloadSignature",
          "entity": "signature"
        },
        {
          "component": "dropdown-menu",
          "as": "downloadMenu",
          "entity": "signature"
        },
        {
          "component": "icon-button",
          "as": "shareSignature",
          "entity": "signature"
        },
        {
          "component": "dropdown-menu",
          "as": "shareMenu",
          "entity": "signature"
        },
        {
          "component": "icon-button",
          "as": "deleteSignature",
          "entity": "signature"
        },
        {
          "component": "dialog",
          "as": "deleteConfirmation",
          "entity": "signature"
        },
        {
          "component": "select",
          "as": "operatorSigner"
        },
        {
          "component": "select",
          "as": "operatorChannel"
        },
        {
          "component": "select",
          "as": "signerPerson",
          "entity": "signer"
        },
        {
          "component": "select",
          "as": "signerChannel",
          "entity": "signer"
        },
        {
          "component": "switch",
          "as": "otpWaiver",
          "entity": "signer"
        },
        {
          "component": "select",
          "as": "batchChannel"
        },
        {
          "component": "switch",
          "as": "batchOtpWaiver"
        },
        {
          "component": "alert",
          "as": "otpWarning",
          "entity": "signer"
        },
        {
          "component": "alert",
          "as": "batchOtpWarning"
        },
        {
          "component": "alert",
          "as": "minorSignerWarning",
          "entity": "signer"
        },
        {
          "component": "alert",
          "as": "minorPatientWarning"
        },
        {
          "component": "link",
          "as": "contactAction",
          "entity": "signer"
        },
        {
          "component": "alert",
          "as": "submissionError"
        },
        {
          "component": "button",
          "as": "assignToMe"
        },
        {
          "component": "button",
          "as": "addSigner"
        },
        {
          "component": "button",
          "as": "addSignee"
        },
        {
          "component": "icon-button",
          "as": "removeSigner",
          "entity": "signer"
        },
        {
          "component": "button",
          "as": "requestSignature"
        },
        {
          "component": "list",
          "as": "recipientList"
        },
        {
          "component": "button",
          "as": "confirmSend"
        },
        {
          "component": "button",
          "as": "confirmBack"
        },
        {
          "component": "button",
          "as": "close"
        },
        {
          "component": "spinner",
          "as": "qrPending"
        },
        {
          "component": "qr-code",
          "as": "signingQrCode",
          "entity": "signer"
        },
        {
          "component": "alert",
          "as": "qrMissing",
          "entity": "signer"
        },
        {
          "component": "button",
          "as": "qrPrevious"
        },
        {
          "component": "button",
          "as": "qrNext"
        },
        {
          "component": "button",
          "as": "qrDone"
        },
        {
          "component": "list",
          "as": "requiredItemsList",
          "entity": "requiredItem"
        },
        {
          "component": "skeleton",
          "as": "requiredItemsLoading"
        },
        {
          "component": "select",
          "as": "itemOperator",
          "entity": "requiredItem"
        },
        {
          "component": "select",
          "as": "itemOperatorChannel",
          "entity": "requiredItem"
        },
        {
          "component": "button",
          "as": "assignAllToMe"
        },
        {
          "component": "alert",
          "as": "assignLaterNote"
        },
        {
          "component": "alert",
          "as": "operatorChannelNote"
        },
        {
          "component": "button",
          "as": "buyMoreSignatures"
        },
        {
          "component": "button",
          "as": "outcomeCancel"
        }
      ],
      "workflows": [
        {
          "name": "review_signatures",
          "safety": "phi",
          "description": "When the host passes `signatures` (or `signaturesLoading`), the request form shows the document's past signature requests at its top, on the same screen as the operator and signers, as on platform: a table named Signed versions (section data-section=\"signed-versions\") with the columns Date, Signature type and Actions and one row per request (data-signature-id), newest first. Date is the weekday, date and time in the active locale; Signature type is the legal level (Simple or Advanced, hidden with showLegalLevel=false), the channel (SMS, e-mail, WhatsApp, on this device or Via QR) and a SignatureStatusChip whose tooltip names who signed, who is still awaited and who signed on a party's behalf. Loading shows skeleton rows; no records shows one line saying there are no signed versions. Hosts that pass neither prop get the plain form.",
          "descriptionKey": "ui.agent.signatureRequest.workflows.reviewSignatures",
          "uiActions": [],
          "stateReads": [
            "dialog.isOpen"
          ],
          "apiActions": [
            "signature.list"
          ]
        },
        {
          "name": "view_signature",
          "safety": "phi",
          "description": "Open one signed document from its row's View button; the host receives onViewSignature(id). The button shows only when the host passes that callback.",
          "descriptionKey": "ui.agent.signatureRequest.workflows.viewSignature",
          "uiActions": [],
          "apiActions": [
            "signature.view"
          ]
        },
        {
          "name": "download_signature",
          "safety": "phi",
          "description": "Download one signed document from its row; the host receives onDownloadSignature(id, 'full' | 'anonymised'). When the record has an anonymised version the Download button opens a menu with Full version and Anonymised version (menu id signature-download-<record id>); otherwise it asks for 'full' directly. The button shows only when the host passes that callback.",
          "descriptionKey": "ui.agent.signatureRequest.workflows.downloadSignature",
          "uiActions": [
            "dropdown-menu.open",
            "dropdown-menu.close"
          ],
          "stateReads": [
            "dropdown-menu.isOpen"
          ],
          "apiActions": [
            "signature.download"
          ]
        },
        {
          "name": "share_signature",
          "safety": "phi",
          "description": "Share one signed document from its row's Share menu (menu id signature-share-<record id>): link, e-mail or WhatsApp, in that order. The host receives onShareSignature(id, 'link' | 'email' | 'whatsapp') and does the sharing. The host decides which targets a row offers: the record's shareTargets, else the modal's signatureShareTargets, else all three. The button shows only when the host passes that callback and the row has at least one target.",
          "descriptionKey": "ui.agent.signatureRequest.workflows.shareSignature",
          "uiActions": [
            "dropdown-menu.open",
            "dropdown-menu.close"
          ],
          "stateReads": [
            "dropdown-menu.isOpen"
          ],
          "apiActions": [
            "signature.share"
          ]
        },
        {
          "name": "delete_signature",
          "safety": "destructive",
          "description": "Delete one signed document from its row's Delete button. It opens a confirmation, an alert dialog (dialog id signature-delete-<record id>) asking whether to delete this signed document, with the row's date under the question and Cancel and Delete. Only Delete calls onDeleteSignature(id); the host deletes and drops the record. Cancel, Esc or dialog.close / dialog.dismiss close it without deleting, and focus returns to the row's Delete button. Once the host drops the record, focus moves to the next row's first action (else the previous row's, else the line saying there are no signed versions) and a polite status says the signature was deleted. The button shows only when the host passes that callback.",
          "descriptionKey": "ui.agent.signatureRequest.workflows.deleteSignature",
          "uiActions": [
            "dialog.close",
            "dialog.dismiss"
          ],
          "stateReads": [
            "dialog.isOpen"
          ],
          "apiActions": [
            "signature.delete"
          ]
        },
        {
          "name": "assign_operator",
          "safety": "write",
          "description": "Pick the operator who must counter-sign (or \"Assign later\" to leave the request unassigned). The operators are listed in host order, then \"Assign later\". An operator the host marks disabled shows greyed out with the host's reason under the name (the trigger is described by every greyed-out operator and reason) and cannot be picked; set_value refuses them. An operator the host marks deleted is listed only while they are the current value, and is never seeded. \"Assign to me\" claims it for the signed-in operator.",
          "descriptionKey": "ui.agent.signatureRequest.workflows.assignOperator",
          "uiActions": [
            "select.set_value"
          ],
          "stateReads": [
            "select.value"
          ],
          "apiActions": []
        },
        {
          "name": "manage_signer_roster",
          "safety": "write",
          "description": "Build the patient-side signer roster: pick who signs in each row (the patient or their configured signee, e.g. a legal guardian), add a second signer up to the cap, or remove a row. People already on the roster are excluded from the other rows; set_value with one of them, or anyone not offered in that row, leaves the row unchanged. In required documents mode the roster signs the whole batch: the main signer (row data-signer-role=\"main\"), then at most one second signee (data-signer-role=\"second\", a group named Second signee). The second signee is offered only when every listed item is a document that can carry a second signature (anamnesis interviews never can), the main signer's channel is on this device (the batch channel with channelMode batch, else the main signer's own row), and the main signer is a registered signee, not the patient (isPatient); otherwise Add signer is disabled and a visible line says why. The patient is never offered as the second signee. Changing the main signer removes the second signee, announced via a live region. Moving the main signer's channel off this device only hides them (they are not submitted) and announces why; back on this device they return. Per signer, the second signee has their own channel beside their name. A second signee who is the main signer again, is no longer on offer, or cannot receive their own channel (the batch channel in batch mode) shows a message under their row (data-note=\"second-signee-issue\") and keeps Request signature disabled. When the host marks the patient (the isPatient option) as under 18 (isMinor), a warning under the Patient signers heading (data-note=\"minor-patient\", data-warning addSignee, selectSignee, selectSecondSignee or addSecondSignee) gives platform's advice from the roster: with no registered signee on the roster, add a parent or guardian (none registered) or choose one (one registered); with one signee and a free second seat, have the other parent or guardian sign too (another registered) or add them (none). With two signees, or no second seat, it says nothing. Any other person marked isMinor gets a general reminder in their own row (data-note=\"minor-signer\"). Neither blocks the request, and the kit does not compute age. A link-style Add signatory button calls the host's onAddSignee: inside the minor patient warning when it asks to add someone, and in required documents mode under the Patient signers heading while the patient has no registered signee (no signer option without isPatient), only once. Add signatory is user-driven with no adapter action, and the host adds the new person to signerOptions. With signerAddAction createSignee, the button beside the Patient signers heading is Add signatory (data-action=\"create-signee\") and calls onAddSignee instead of adding a row; the minor patient warning then has no button. With secondSigneeSlot (request form, maxSigners 2 or more), an Add signer button beside the heading (data-action=\"add-second-signee\") opens a line (data-second-signee-slot) with a select named Second signee; it shows only while one can be seated (a registered signee is the main signer and another is registered). With secondSigneeSlot or signerAddAction createSignee, every signer dropdown ends with a New signatory option that calls onAddSignee (the host's create-signee page) and leaves the row unchanged. New signatory is user-driven; set_value refuses it. The line offers registered signees only and has a Remove signer button that takes it away again; picking one seats the second signee (data-signer-role=\"second\"), whose Remove signer also takes the line away. While the patient is the main signer a visible line under the heading says why there is no second signee (data-note=\"second-signee-hint\"). A new main signer clears the second signee, announced via a live region.",
          "descriptionKey": "ui.agent.signatureRequest.workflows.manageSignerRoster",
          "uiActions": [
            "select.set_value"
          ],
          "stateReads": [
            "select.value"
          ],
          "apiActions": []
        },
        {
          "name": "choose_delivery_channel",
          "safety": "write",
          "description": "Choose how each signer's request is delivered in the channel dropdown beside their name, a select named Signature channel (one choice): SMS, e-mail, WhatsApp, signing on this device, or via QR (the signer scans a QR code the dialog shows in its QR step after the request; offered to every patient-side signer by default). Each signer row (data-signer-id) holds its dropdown, with the id signature-request-signer-channel-<row number>; the operator dropdown's id is signature-request-operator-channel. Each option carries data-option-id with the channel; set_value with a channel the dropdown does not offer or has disabled leaves the choice unchanged. A signer's available channels can hide any of these, Via QR included. A signer's unavailableChannels instead show a channel greyed out with the host's reason under it (e.g. SMS and WhatsApp with No mobile number): set_value refuses it, the row never falls back to it, and a signer with no channel left shows the reasons under the row and keeps Request signature disabled. When the host gives a greyed-out channel an actionHref, a link under the person (data-note=\"contact-actions\"), such as Add mobile number or Add e-mail address, leads to the host's page to fix it; in batch mode the main signer's links show under the batch channel select. They are plain links with no adapter action. On-device signers sign sequentially in roster order. The assigned operator has the same dropdown, named Operator signature channel, with SMS, e-mail, or on this device, WhatsApp only when the host rule lists it in operatorAvailableChannels (as platform does for operator-only documents), and never Via QR: the operator's own system-defined channel (defaultChannel, from their settings) arrives preselected and follows a newly picked operator, while a channel changed by hand is kept until the operator changes; the on-device option is enabled only while a patient signer also signs on this device (while disabled, its reason shows under the option and describes the trigger; an automatic fallback to the operator's default is announced via a live region when the last on-device patient row leaves). A host can replace that rule with resolveChannels: it receives the choices after every channel change (and on open) and returns the channels to use and to offer, e.g. the operator and the patient on this device together; set_value may then move another person's channel too (the operator or another signer), announced via the same live region. Channels are per signer by default, in the request form and in required documents mode. With channelMode batch there is no channel beside each name: one labelled Signature channel select (id signature-request-batch-channel) under the signers heading sets the channel for the whole roster, with SMS, e-mail, WhatsApp and Via QR offered when the main signer or the patient (isPatient) can receive them, greyed out only when neither can, and on this device always offered. It starts on e-mail, or SMS when the main signer is the patient and can receive it, unless the host passes initialBatchChannel; in required documents mode changing the main signer returns it to that default (initialBatchChannel is read only on open), announced via the live region. resolveChannels receives the batch channel as every signer's channel and moves the batch through the main signer's returned channel. In required documents mode with showOperatorChannels, each item with an assigned operator also has that operator's channel select (SMS, e-mail or on this device), named Operator signature channel for <item name> with the id signature-request-item-operator-channel-<item id>; it starts on the operator's defaultChannel and follows a newly picked operator (Assign to me included), keeping a channel changed by hand until then. Items on Assign later have none. With batchChannelPlacement inline, the batch select (same id) sits in the main signer's row instead of under the heading, and any other signer shows the batch channel as read-only text (data-note=\"batch-channel\"). With linkOnDevice, the operator signs on this device exactly when the patient side does: set_value On this device on the operator's channel also moves the main signer (or the batch) there, while the patient side is on this device the operator's other channels are disabled with the reason, and when it leaves the operator returns to their default, each announced via the live region.",
          "descriptionKey": "ui.agent.signatureRequest.workflows.chooseDeliveryChannel",
          "uiActions": [
            "select.set_value"
          ],
          "stateReads": [
            "select.value"
          ],
          "apiActions": []
        },
        {
          "name": "waive_otp",
          "safety": "write",
          "description": "Toggle a signer's on-device OTP waiver. Waiving OTP lowers the evidentiary value of that signature; the pattern surfaces a warning alert while waived. With channelMode batch there is one switch for the whole roster (Do not require OTP from the patient), shown only while the batch channel is on this device: it starts on when the patient cannot receive SMS, whoever the main signer is, and is on and disabled when the main signer is the patient and cannot receive SMS. The choice resets when the batch channel changes. Its warning (batchOtpWarning) is one batch-level alert outside every signer row; as on platform it shows while the waiver is on, and on every channel while it is forced. Per signer in required documents mode, the main signer's own switch follows the same rules (starts on, or on and disabled, described by the warning) and resets when that row's channel changes; other rows are the user's choice.",
          "descriptionKey": "ui.agent.signatureRequest.workflows.waiveOtp",
          "uiActions": [
            "switch.toggle",
            "switch.set_checked"
          ],
          "stateReads": [
            "switch.checked"
          ],
          "apiActions": []
        },
        {
          "name": "request_signature",
          "safety": "phi",
          "description": "Send the signature request. Notifies every roster signer over their selected channel and hands the submission to the host. With confirmRecipients, when anyone is reached by SMS, e-mail or WhatsApp, Request signature first shows the recipient check (see confirm_recipients) and nothing is handed over until Send. When any signer chose Via QR the dialog stays open and moves to its QR step. With channelMode batch the submission carries signMode (the batch channel, also on every signer). In required documents mode it also carries operatorAssignments (item id to operator id, null for assign later), requiredItemIds and, with showOperatorChannels, operatorChannels (item id to the operator's channel, for assigned items), with operatorChannel null; the main signer OTP waiver is skipOtp on the main signer, set only on this device. While the host passes loading, the dialog shows skeleton rows (data-note=\"loading\", aria-busy) and Request signature is disabled; the form seeds when loading ends.",
          "descriptionKey": "ui.agent.signatureRequest.workflows.requestSignature",
          "uiActions": [
            "dialog.close"
          ],
          "stateReads": [
            "select.value",
            "switch.checked",
            "dialog.isOpen"
          ],
          "apiActions": [
            "signature.request"
          ]
        },
        {
          "name": "confirm_recipients",
          "safety": "phi",
          "description": "With confirmRecipients, a request that reaches anyone by SMS, e-mail or WhatsApp first shows a step headed \"Send the signature request?\" listing each recipient (list items with data-recipient=\"operator\" or \"signer\"): the assigned operator in the request form, then every roster signer on a remote channel, with their channel and the phone number or e-mail address the host gave as their contact. Send hands the submission to the host; Back returns to the form with nothing sent. On this device and Via QR need no check. The step stays while the host is busy; a new error returns to the form and an outcome replaces it. Send and Back are user-driven buttons with no adapter action; the contact is shown as text only, never in a DOM hook.",
          "descriptionKey": "ui.agent.signatureRequest.workflows.confirmRecipients",
          "uiActions": [
            "dialog.close",
            "dialog.dismiss"
          ],
          "stateReads": [
            "dialog.isOpen"
          ],
          "apiActions": []
        },
        {
          "name": "show_qr_code",
          "safety": "phi",
          "description": "After a request with a signer on the Via QR channel, the same dialog shows its QR step: a loading state until the host passes the server-issued links, then one code per QR signer with the signer name and expiry (the code or its error carries data-signer-id). With several QR signers, the user moves between codes with Previous and Next (\"1 of 2\"); Done on the last code tells the host the codes were handed over (onQrDone) and closes the dialog. Previous, Next and Done are user-driven buttons with no adapter action. Closing through dialog.close, or dismissing the waiting state with dialog.dismiss, does not fire onQrDone. A QR signer with no link shows an error in place of the code. The operator is never offered Via QR.",
          "descriptionKey": "ui.agent.signatureRequest.workflows.showQrCode",
          "uiActions": [
            "dialog.close",
            "dialog.dismiss"
          ],
          "stateReads": [
            "qr-code.value",
            "dialog.isOpen"
          ],
          "apiActions": []
        },
        {
          "name": "review_required_items",
          "safety": "phi",
          "description": "When the host passes `requiredItems` (or `requiredItemsLoading`), the form asks one patient to sign every outstanding item in one batch: documents to sign and anamnesis interviews to complete, as two lists named with their counts. Each row (data-required-item-id) shows the item name only, with no signing status: the documents API of the host says only whether an item is signed. Items marked signed are left out; when none is left the dialog shows the all signed outcome. Loading shows skeleton rows. The single operator row and the signed versions table do not appear in this mode.",
          "descriptionKey": "ui.agent.signatureRequest.workflows.reviewRequiredItems",
          "uiActions": [],
          "stateReads": [
            "dialog.isOpen"
          ],
          "apiActions": [
            "signature.listRequired"
          ]
        },
        {
          "name": "assign_item_operators",
          "safety": "write",
          "description": "In required documents mode, pick the operator for each item that needs an operator signature (requiresOperator), or \"Assign later\", listed first. Each picker is named \"Operator for <item name>\" and has the id signature-request-item-operator-<item id>. Greyed-out and deleted operators follow the same rules as the single operator picker: a disabled operator shows its reason and set_value refuses them, a deleted one shows only in a picker still assigned to them. \"Assign to me\" (shown when the host passes currentOperatorId) sets every picker to the signed-in operator; it is a user-driven button with no adapter action. An info note shows while any picker is on Assign later, and another says each operator receives the request by e-mail or SMS per their own settings, unless the host passes showOperatorChannels: then each assigned item shows its operator's channel instead (see choose_delivery_channel).",
          "descriptionKey": "ui.agent.signatureRequest.workflows.assignItemOperators",
          "uiActions": [
            "select.set_value"
          ],
          "stateReads": [
            "select.value"
          ],
          "apiActions": []
        },
        {
          "name": "show_outcome",
          "safety": "read",
          "description": "When the host passes `outcome`, the dialog replaces every other view with a final screen whose heading and description carry the message, and focus moves to the heading: 'linkSent' (the secure link went out; in required documents mode the heading says the documents were sent to the patient), 'allSigned' (nothing left to sign) or 'creditsExhausted' (no electronic signature documents left). Close ends it; on 'creditsExhausted' a Buy more documents button calls onBuyMoreSignatures when the host passes it, and a Cancel button, when the host passes onOutcomeCancel, returns the dialog to the form and calls it so the host clears outcome (both user-driven, no adapter action).",
          "descriptionKey": "ui.agent.signatureRequest.workflows.showOutcome",
          "uiActions": [
            "dialog.close",
            "dialog.dismiss"
          ],
          "stateReads": [
            "dialog.isOpen"
          ],
          "apiActions": []
        },
        {
          "name": "dismiss",
          "safety": "destructive",
          "description": "Close the modal without sending a signature request. Discards the in-progress operator, roster, channel, and OTP choices.",
          "descriptionKey": "ui.agent.signatureRequest.workflows.dismiss",
          "uiActions": [
            "dialog.dismiss"
          ],
          "stateReads": [
            "dialog.isOpen"
          ],
          "apiActions": []
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "signed-out-frame",
      "composes": [
        {
          "component": "app-frame",
          "as": "frame"
        },
        {
          "component": "header",
          "as": "header"
        },
        {
          "component": "logo",
          "as": "brand"
        },
        {
          "component": "button",
          "as": "headerLink"
        },
        {
          "component": "public-footer",
          "as": "footer"
        }
      ],
      "workflows": [
        {
          "name": "read_page",
          "safety": "read",
          "description": "Read the page a signed-out visitor is on. The page's content is inside `<main>` (the header's skip link points at it). The header (`role=\"banner\"`) holds the brand link and, when the host gives their addresses, links to the other signed-out pages: `data-action=\"login\"`, `data-action=\"register-doctor\"`, `data-action=\"register-patient\"`. There is no search, inbox or account menu before sign-in. The footer (`role=\"contentinfo\"`) links to the privacy policy and the terms.",
          "descriptionKey": "ui.agent.signedOutFrame.workflows.readPage",
          "uiActions": [],
          "apiActions": []
        },
        {
          "name": "go_to_sign_in",
          "safety": "read",
          "description": "Follow the header's \"Sign in\" link (`data-action=\"login\"`). Present on a registration or forgot-password page, when the host gives its address.",
          "descriptionKey": "ui.agent.signedOutFrame.workflows.goToSignIn",
          "uiActions": [],
          "apiActions": []
        },
        {
          "name": "go_to_registration",
          "safety": "read",
          "description": "Follow one of the header's registration links: `data-action=\"register-doctor\"` or `data-action=\"register-patient\"`. Present on the login page, for each address the host gives. Each link is in the page twice, once with its label for wide screens and once as an icon for narrow ones, and only one of the two is shown: follow the one that is visible.",
          "descriptionKey": "ui.agent.signedOutFrame.workflows.goToRegistration",
          "uiActions": [],
          "apiActions": []
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "signing",
      "composes": [
        {
          "component": "header",
          "as": "brandBar"
        },
        {
          "component": "pdf-viewer",
          "as": "document"
        },
        {
          "component": "signature-field",
          "as": "fieldOverlay",
          "entity": "signatureField"
        },
        {
          "component": "dialog",
          "as": "captureDialog"
        },
        {
          "component": "signature-capture",
          "as": "capturePad"
        },
        {
          "component": "otp-input",
          "as": "gateCode"
        },
        {
          "component": "checkbox",
          "as": "gateConfirm"
        },
        {
          "component": "alert",
          "as": "gateNotice"
        },
        {
          "component": "card",
          "as": "gateCard"
        },
        {
          "component": "button",
          "as": "gateVerify"
        },
        {
          "component": "finished-terminal",
          "as": "terminal"
        },
        {
          "component": "avatar",
          "as": "rosterAvatar",
          "entity": "signer"
        },
        {
          "component": "badge",
          "as": "rosterStatus",
          "entity": "signer"
        },
        {
          "component": "empty-state",
          "as": "invalidLink"
        },
        {
          "component": "spinner",
          "as": "loading"
        }
      ],
      "workflows": [
        {
          "name": "verify_identity",
          "safety": "write",
          "description": "Pass the identity gate before the document is shown: enter the 5-character SMS code, or tick the confirm-identity checkbox when no mobile number is on file, then verify.",
          "descriptionKey": "ui.agent.signing.workflows.verifyIdentity",
          "uiActions": [
            "otp-input.set_value",
            "checkbox.set_checked"
          ],
          "stateReads": [
            "otp-input.isComplete",
            "checkbox.checked"
          ],
          "apiActions": [
            "signing.verifyIdentity",
            "signing.resendCode"
          ]
        },
        {
          "name": "read_document",
          "safety": "read",
          "description": "Page through and zoom the document under signature before signing each field.",
          "descriptionKey": "ui.agent.signing.workflows.readDocument",
          "uiActions": [
            "pdf-viewer.go_to_page",
            "pdf-viewer.set_zoom"
          ],
          "apiActions": []
        },
        {
          "name": "sign_field",
          "safety": "write",
          "description": "Activate a signature / initial / date field overlay, draw or type the signature in the capture dialog, and confirm it. Signing the last field auto-advances to the success terminal.",
          "descriptionKey": "ui.agent.signing.workflows.signField",
          "uiActions": [
            "dialog.open",
            "signature-capture.clear",
            "signature-capture.undo",
            "signature-capture.confirm"
          ],
          "stateReads": [
            "signature-capture.isEmpty",
            "dialog.isOpen"
          ],
          "apiActions": [
            "signing.applyFieldSignature"
          ]
        },
        {
          "name": "complete_envelope",
          "safety": "write",
          "description": "Finalise the envelope once every required field carries a signature (with two signees: once both the primary and the secondary have signed all of their fields), persisting the completed document.",
          "descriptionKey": "ui.agent.signing.workflows.completeEnvelope",
          "uiActions": [],
          "apiActions": [
            "signing.completeEnvelope"
          ]
        },
        {
          "name": "verify_signee_identity",
          "safety": "write",
          "description": "The active signee (primary or secondary) passes its own identity gate: enter the 5-character SMS code, or tick the confirm-identity checkbox when no mobile number is on file, then verify.",
          "descriptionKey": "ui.agent.signing.workflows.verifySigneeIdentity",
          "uiActions": [
            "otp-input.set_value",
            "checkbox.set_checked"
          ],
          "stateReads": [
            "otp-input.isComplete",
            "checkbox.checked"
          ],
          "apiActions": [
            "signing.verifySigneeIdentity",
            "signing.resendCode"
          ]
        },
        {
          "name": "sign_signee_fields",
          "safety": "write",
          "description": "The active signee signs the surface filtered to its own fields: activate a field overlay, draw or type the signature in the capture dialog, and confirm it.",
          "descriptionKey": "ui.agent.signing.workflows.signSigneeFields",
          "uiActions": [
            "pdf-viewer.go_to_page",
            "dialog.open",
            "signature-capture.clear",
            "signature-capture.undo",
            "signature-capture.confirm"
          ],
          "stateReads": [
            "signature-capture.isEmpty",
            "dialog.isOpen"
          ],
          "apiActions": [
            "signing.applySigneeFieldSignature"
          ]
        },
        {
          "name": "hand_off_to_secondary_signee",
          "safety": "write",
          "description": "After the primary signee finishes, hand the device to the secondary signee (same-device flow), switching the active session and re-filtering the surface to the secondary signee’s fields.",
          "descriptionKey": "ui.agent.signing.workflows.handOffToSecondarySignee",
          "uiActions": [],
          "apiActions": [
            "signing.handOffToSecondarySignee"
          ]
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "tasks",
      "composes": [
        {
          "component": "data-table",
          "as": "roster",
          "entity": "task"
        },
        {
          "component": "warning-stack",
          "as": "notices"
        },
        {
          "component": "switch",
          "as": "doneToggle"
        },
        {
          "component": "button",
          "as": "noticeAction"
        },
        {
          "component": "icon-button-group",
          "as": "tableActions"
        },
        {
          "component": "icon-button",
          "as": "tableAction"
        },
        {
          "component": "smart-date",
          "as": "dueDate"
        }
      ],
      "workflows": [
        {
          "name": "filter_tasks",
          "safety": "read",
          "description": "Narrow the roster by title, type, assignee, due range or status using the per-column filters.",
          "descriptionKey": "ui.agent.tasks.workflows.filterTasks",
          "uiActions": [
            "data-table.apply_filter"
          ],
          "stateReads": [
            "data-table.filter"
          ],
          "apiActions": [
            "task.list"
          ]
        },
        {
          "name": "filter_from_notice",
          "safety": "read",
          "description": "Apply a WarningStack notice’s \"View\" action (e.g. \"View overdue\", \"View collections\") to narrow the roster to the flagged tasks.",
          "descriptionKey": "ui.agent.tasks.workflows.filterFromNotice",
          "uiActions": [
            "data-table.apply_filter"
          ],
          "stateReads": [
            "data-table.filter"
          ],
          "apiActions": []
        },
        {
          "name": "sort_roster",
          "safety": "read",
          "description": "Re-sort the roster by any column (e.g. soonest due first, created date).",
          "descriptionKey": "ui.agent.tasks.workflows.sortRoster",
          "uiActions": [
            "data-table.sort_by"
          ],
          "stateReads": [
            "data-table.sort"
          ],
          "apiActions": []
        },
        {
          "name": "toggle_done",
          "safety": "write",
          "description": "Mark a task as done (or reopen it) via its per-row done toggle.",
          "descriptionKey": "ui.agent.tasks.workflows.toggleDone",
          "uiActions": [
            "switch.set_checked"
          ],
          "stateReads": [
            "switch.checked"
          ],
          "apiActions": [
            "task.setDone"
          ]
        },
        {
          "name": "compact_actions",
          "safety": "read",
          "description": "Toggle the ColumnToggle settings-footer switch to compact the per-row action column.",
          "descriptionKey": "ui.agent.tasks.workflows.compactActions",
          "uiActions": [
            "switch.set_checked"
          ],
          "stateReads": [
            "switch.checked"
          ],
          "apiActions": []
        },
        {
          "name": "export_roster",
          "safety": "read",
          "description": "Export the current (optionally filtered) roster from the page-header table-tools cluster — CSV / Excel / PDF.",
          "descriptionKey": "ui.agent.tasks.workflows.exportRoster",
          "uiActions": [],
          "apiActions": [
            "task.export"
          ]
        },
        {
          "name": "edit_task",
          "safety": "write",
          "description": "Edit the selected task from its row action.",
          "descriptionKey": "ui.agent.tasks.workflows.editTask",
          "uiActions": [
            "data-table.get_selection"
          ],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": [
            "task.update"
          ]
        },
        {
          "name": "delete_task",
          "safety": "destructive",
          "description": "Delete the selected task from its row action. Completed tasks cannot be deleted. Irreversible.",
          "descriptionKey": "ui.agent.tasks.workflows.deleteTask",
          "uiActions": [
            "data-table.get_selection",
            "data-table.clear_selection"
          ],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": [
            "task.delete"
          ]
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "two-factor-login",
      "composes": [
        {
          "component": "card",
          "as": "shell"
        },
        {
          "component": "logo",
          "as": "brandmark"
        },
        {
          "component": "otp-input",
          "as": "code"
        },
        {
          "component": "alert",
          "as": "notice"
        },
        {
          "component": "button",
          "as": "verify"
        },
        {
          "component": "button",
          "as": "resend"
        },
        {
          "component": "button",
          "as": "switchMethod"
        },
        {
          "component": "spinner",
          "as": "verifying"
        }
      ],
      "workflows": [
        {
          "name": "enter_code",
          "safety": "write",
          "description": "Type the 6-digit verification code into the OTP field.",
          "descriptionKey": "ui.agent.twoFactorLogin.workflows.enterCode",
          "uiActions": [
            "otp-input.set_value"
          ],
          "stateReads": [
            "otp-input.value",
            "otp-input.isComplete"
          ],
          "apiActions": []
        },
        {
          "name": "verify_code",
          "safety": "write",
          "description": "Submit the entered code to complete the second-factor challenge and sign in.",
          "descriptionKey": "ui.agent.twoFactorLogin.workflows.verifyCode",
          "uiActions": [
            "otp-input.set_value"
          ],
          "stateReads": [
            "otp-input.isComplete"
          ],
          "apiActions": [
            "twoFactor.verify"
          ]
        },
        {
          "name": "resend_code",
          "safety": "write",
          "description": "Request a fresh SMS code (capped at the configured resend limit).",
          "descriptionKey": "ui.agent.twoFactorLogin.workflows.resendCode",
          "uiActions": [
            "otp-input.clear"
          ],
          "apiActions": [
            "twoFactor.resendCode"
          ]
        },
        {
          "name": "switch_method",
          "safety": "read",
          "description": "Switch between the SMS and authenticator-app verification methods, resetting the entry.",
          "descriptionKey": "ui.agent.twoFactorLogin.workflows.switchMethod",
          "uiActions": [
            "otp-input.clear"
          ],
          "apiActions": [
            "twoFactor.switchMethod"
          ]
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "upgrade-practice",
      "composes": [
        {
          "component": "card",
          "as": "packageCard",
          "entity": "package"
        },
        {
          "component": "button",
          "as": "addToSubscription"
        },
        {
          "component": "button",
          "as": "confirmUpgrade"
        },
        {
          "component": "icon-button",
          "as": "backControl"
        },
        {
          "component": "select",
          "as": "quantityTier"
        },
        {
          "component": "form-field",
          "as": "configureField"
        }
      ],
      "workflows": [
        {
          "name": "view_packages",
          "safety": "read",
          "description": "List the available upgrade packages with their headline benefits and price.",
          "descriptionKey": "ui.agent.upgradePractice.workflows.viewPackages",
          "uiActions": [],
          "apiActions": [
            "subscription.listPackages"
          ]
        },
        {
          "name": "open_package",
          "safety": "read",
          "description": "Open a package card to its detail view with the quantified benefit rows.",
          "descriptionKey": "ui.agent.upgradePractice.workflows.openPackage",
          "uiActions": [],
          "apiActions": [
            "subscription.getPackage"
          ]
        },
        {
          "name": "configure_package",
          "safety": "read",
          "description": "In the basket, set the quantity or tier for a tiered/quantity package and read back the chosen value; the monthly-price-increase summary recomputes.",
          "descriptionKey": "ui.agent.upgradePractice.workflows.configurePackage",
          "uiActions": [
            "select.set_value"
          ],
          "stateReads": [
            "select.value"
          ],
          "apiActions": [
            "subscription.previewUpgrade"
          ]
        },
        {
          "name": "confirm_upgrade",
          "safety": "write",
          "description": "Confirm the upgrade — add the configured package to the practice subscription and bill the prorated partial period. Persists a billing change.",
          "descriptionKey": "ui.agent.upgradePractice.workflows.confirmUpgrade",
          "uiActions": [],
          "apiActions": [
            "subscription.addPackage"
          ]
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "warehouse",
      "composes": [
        {
          "component": "data-table",
          "as": "inventory",
          "entity": "inventoryItem"
        },
        {
          "component": "icon-button-group",
          "as": "tableActions"
        },
        {
          "component": "icon-button",
          "as": "tableAction"
        },
        {
          "component": "badge",
          "as": "statusBadge"
        },
        {
          "component": "switch",
          "as": "compactActionsToggle"
        },
        {
          "component": "dialog",
          "as": "importDialog"
        },
        {
          "component": "file-upload",
          "as": "xmlUpload"
        }
      ],
      "workflows": [
        {
          "name": "filter_inventory",
          "safety": "read",
          "description": "Narrow the inventory by product, SKU, category, supplier or stock status using the per-column filters.",
          "descriptionKey": "ui.agent.warehouse.workflows.filterInventory",
          "uiActions": [
            "data-table.apply_filter"
          ],
          "stateReads": [
            "data-table.filter"
          ],
          "apiActions": [
            "inventory.list"
          ]
        },
        {
          "name": "sort_inventory",
          "safety": "read",
          "description": "Re-sort the inventory by any column (e.g. in-stock, total value, last restocked).",
          "descriptionKey": "ui.agent.warehouse.workflows.sortInventory",
          "uiActions": [
            "data-table.sort_by"
          ],
          "stateReads": [
            "data-table.sort"
          ],
          "apiActions": []
        },
        {
          "name": "compact_actions",
          "safety": "read",
          "description": "Toggle the ColumnToggle settings-footer switch to compact the per-row action column.",
          "descriptionKey": "ui.agent.warehouse.workflows.compactActions",
          "uiActions": [
            "switch.set_checked"
          ],
          "stateReads": [
            "switch.checked"
          ],
          "apiActions": []
        },
        {
          "name": "export_inventory",
          "safety": "read",
          "description": "Export the current (optionally filtered) inventory from the page-header table-tools cluster — CSV / Excel / PDF.",
          "descriptionKey": "ui.agent.warehouse.workflows.exportInventory",
          "uiActions": [],
          "apiActions": [
            "inventory.export"
          ]
        },
        {
          "name": "stock_in",
          "safety": "write",
          "description": "Record incoming stock for the selected item from its row action.",
          "descriptionKey": "ui.agent.warehouse.workflows.stockIn",
          "uiActions": [
            "data-table.get_selection"
          ],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": [
            "inventory.stockIn"
          ]
        },
        {
          "name": "stock_out",
          "safety": "write",
          "description": "Record outgoing stock for the selected item from its row action.",
          "descriptionKey": "ui.agent.warehouse.workflows.stockOut",
          "uiActions": [
            "data-table.get_selection"
          ],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": [
            "inventory.stockOut"
          ]
        },
        {
          "name": "edit_item",
          "safety": "write",
          "description": "Edit the selected inventory item (e.g. min-stock threshold, supplier) from its row action.",
          "descriptionKey": "ui.agent.warehouse.workflows.editItem",
          "uiActions": [
            "data-table.get_selection"
          ],
          "stateReads": [
            "data-table.selection"
          ],
          "apiActions": [
            "inventory.update"
          ]
        },
        {
          "name": "import_fatturapa",
          "safety": "write",
          "description": "Open the FatturaPA XML import dialog, upload supplier e-invoice XML files, review the classified line preview, deselect any unwanted lines, and confirm to create articles and stock movements.",
          "descriptionKey": "ui.agent.warehouse.workflows.importFatturapa",
          "uiActions": [
            "dialog.open",
            "file-upload.clear"
          ],
          "stateReads": [
            "dialog.isOpen",
            "file-upload.files"
          ],
          "apiActions": [
            "inventory.importFatturapa"
          ]
        }
      ]
    },
    {
      "kind": "pattern",
      "id": "workflow-webhook-action",
      "composes": [
        {
          "component": "form-field",
          "as": "field"
        },
        {
          "component": "text-input",
          "as": "url"
        },
        {
          "component": "password-input",
          "as": "secret"
        },
        {
          "component": "button",
          "as": "secretAction"
        },
        {
          "component": "checkbox",
          "as": "legalBasis"
        },
        {
          "component": "accordion",
          "as": "advanced"
        },
        {
          "component": "field-array",
          "as": "parameters",
          "entity": "parameter"
        },
        {
          "component": "token-insert-menu",
          "as": "insertDetail"
        },
        {
          "component": "button",
          "as": "copyField"
        },
        {
          "component": "card",
          "as": "section"
        },
        {
          "component": "badge",
          "as": "parameterCount"
        },
        {
          "component": "alert",
          "as": "parametersError"
        }
      ],
      "workflows": [
        {
          "name": "read_step",
          "safety": "read",
          "description": "Read the webhook step and what is wrong with it. Each field sits in a wrapper with `data-field` (`url`, `secret`, `legalBasisConfirmed`, `parameters`). A field with a problem has `aria-invalid=\"true\"` on its control and its message in a `data-slot=\"error\"` element inside the wrapper. Parameter rows carry `data-parameter-id`, an opaque row id. The `secret` wrapper is write-only for agents: read whether it has a problem, never its value, and never repeat a secret.",
          "descriptionKey": "ui.agent.workflowWebhookAction.workflows.readStep",
          "uiActions": [],
          "apiActions": []
        },
        {
          "name": "generate_secret",
          "safety": "write",
          "description": "Generate a random signing secret into the password field (`data-action=\"generate-secret\"`; again to replace it) and copy it to the clipboard (`data-action=\"copy-secret\"`, which shows `data-copied=\"true\"` once done) so the person can paste it into the receiving app. The secret never appears in the page markup. Nothing is saved until the host form is submitted.",
          "descriptionKey": "ui.agent.workflowWebhookAction.workflows.generateSecret",
          "uiActions": [],
          "apiActions": []
        },
        {
          "name": "edit_parameters",
          "safety": "write",
          "description": "Open the Advanced section (`data-action=\"toggle-advanced\"`) and add, change or remove extra parameters, each a name and a value. Most receiving apps, Link included, need none. A value may contain variables, inserted from each row's \"Insert variable\" menu or copied from the list under the rows (`data-action=\"copy-field\"`); the server replaces them with the patient's details when it sends.",
          "descriptionKey": "ui.agent.workflowWebhookAction.workflows.editParameters",
          "uiActions": [],
          "apiActions": []
        },
        {
          "name": "send_test",
          "safety": "write",
          "description": "Send one sample message to the address (`data-action=\"send-test\"`, present only when the host supports it): sample IDs, no patient data, signed with the secret. The address and secret are checked first. The answer is in `data-slot=\"test-result\"`, with `data-test-ok=\"true\"` when the app answered 2xx.",
          "descriptionKey": "ui.agent.workflowWebhookAction.workflows.sendTest",
          "uiActions": [],
          "apiActions": [
            "workflowAction.sendTest"
          ]
        },
        {
          "name": "read_message_shape",
          "safety": "read",
          "description": "Open \"What Alfadocs sends\" (`data-action=\"toggle-reference\"`) to read what every message carries: an example body and example headers, each in a code block with its own copy button, then each field and header with its meaning. `data-action=\"copy-field\"` copies one field name and shows `data-copied=\"true\"` once done. The example values are invented; the shape is the platform's.",
          "descriptionKey": "ui.agent.workflowWebhookAction.workflows.readMessageShape",
          "uiActions": [],
          "apiActions": []
        },
        {
          "name": "save_step",
          "safety": "phi",
          "description": "Save through the host's own form and button. The fields stop the submit while the address, the secret, the consent box or a parameter name has a problem, and move focus to the first one. The person ticks the consent box themselves: it confirms the practice has a legal basis to share patient data.",
          "descriptionKey": "ui.agent.workflowWebhookAction.workflows.saveStep",
          "uiActions": [],
          "apiActions": [
            "workflowAction.save"
          ]
        }
      ]
    }
  ]
}
