# @nostr-governance/widget Drop-in custom elements for governance UI. Framework-agnostic, no build step required for consumers, and built strictly on the published API. ## The rule these elements follow **They render decisions and issue commands. They compute no policy.** If an element here ever needed to compare a count to a threshold, that would mean the policy definition is missing a profile — not that the widget needs a number. Keeping that line is the whole reason the engine was extracted. ## Elements ### Viewer-facing | Element | Purpose | | --- | --- | | `` | Wraps content and applies the decision: blur on `restrict`, disclosure on `hide`, warning on `warn` | | `` | Report dialog. Requires no capability — anyone may report | | `` | Readout of effect, reasons, and evidence | ### Moderator-facing | Element | Purpose | | --- | --- | | `` | What the signed-in account may actually do | | `` | A capability-gated button that explains refusals | | `` | Effective state, contributor attribution, and controls | ## Usage ```html ``` Elements receive a runtime; they never construct one. A widget that owned relay connections would make it impossible to share one governance runtime across a page. ## Events All events are `composed` so they cross shadow boundaries. | Event | Fired when | | --- | --- | | `governance:revealed` | The viewer chose to show hidden content | | `governance:reported` / `governance:report-failed` | A report was published or refused | | `governance:action-completed` / `:action-refused` / `:action-failed` | An action resolved | | `governance:account-restricted` | The admin panel restricted an account | ## Wording The engine emits stable reason identifiers, never prose, so applications phrase them for their own audience: ```js veil.reasonText = { "admin-user-deny": "This seller is suspended", "trusted-report-threshold": "Flagged by several buyers you follow", }; ``` ## Design decisions worth knowing **Hidden content is removed from the accessibility tree**, not merely covered. A screen reader must not read out something the viewer was not meant to see. **A hidden decision renders a disclosure, not nothing.** Content that silently vanishes is indistinguishable from a bug and leaves no route to appeal. Where the profile permits an override, a "Show anyway" control appears; where it does not, the reason still does. **Refused actions stay visible and explain themselves.** A moderator who cannot see that they lack a capability will assume the tool is broken, and a hidden button teaches nothing about the authority model. The command layer enforces the same check independently — the UI is an explanation, never the gate. **Styling is yours.** Elements expose `part` attributes and inherit `color` and `font` from the host. Override the CSS custom properties (`--gov-fg`, `--gov-surface`, `--gov-warn`, `--gov-danger`, `--gov-radius`) or target parts: ```css governance-veil::part(veil) { border: 1px solid red; } ``` ## Environment `defineGovernanceElements()` is safe to call repeatedly and safe to import in Node — registration is a no-op without a DOM, so a server-rendering host can import the helpers without guarding.