diff --git a/docs/assets/VENDORED.md b/docs/assets/VENDORED.md
deleted file mode 100644
index 6cda9aa..0000000
--- a/docs/assets/VENDORED.md
+++ /dev/null
@@ -1,61 +0,0 @@
-# Vendored assets
-
-Everything in this directory is copied from another repository. It is
-machine-owned: do not edit any of it in place. To update, re-vendor from a tag
-and record the new version here and in the header of each file.
-
-## Instrument Workshop
-
-| Item | Value |
-|---|---|
-| Source | [`trsdn/design-system`](https://github.com/trsdn/design-system) |
-| Version | **v1.5.1** |
-| Vendored on | 2026-09-17 |
-
-| File here | Source path |
-|---|---|
-| `core.tokens.css` | `tokens/generated/web/core.tokens.css` |
-| `instrument-workshop.css` | `src/web/styles/instrument-workshop.css` |
-| `instrument-workshop-fonts.css` | `assets/instrument-workshop-fonts.css` |
-| `fonts/ibm-plex/*.woff2` | `assets/fonts/ibm-plex/*.woff2` |
-
-Copying rather than depending is deliberate and is expressly permitted by the
-[Repository Quality Standard](https://github.com/trsdn/.github/blob/main/docs/repository-quality-standard.md#design-language):
-the design system is maintained privately, so a public site cannot resolve it at
-build time, and a vendored copy keeps rendering when the source moves.
-
-### Re-vendoring
-
-```bash
-VERSION=v1.5.1
-for f in tokens/generated/web/core.tokens.css \
- src/web/styles/instrument-workshop.css \
- assets/instrument-workshop-fonts.css; do
- gh api "repos/trsdn/design-system/contents/$f?ref=$VERSION" \
- -H "Accept: application/vnd.github.raw" > "docs/assets/$(basename "$f")"
-done
-for f in IBMPlexSans-Regular IBMPlexSans-Medium IBMPlexSans-SemiBold \
- IBMPlexMono-Regular IBMPlexMono-SemiBold; do
- gh api "repos/trsdn/design-system/contents/assets/fonts/ibm-plex/$f.woff2?ref=$VERSION" \
- -H "Accept: application/vnd.github.raw" > "docs/assets/fonts/ibm-plex/$f.woff2"
-done
-```
-
-Then restore the vendoring header at the top of each CSS file and update the
-version in this document.
-
-### Recorded deviations
-
-None. The site uses the design language as published.
-
-## IBM Plex
-
-`fonts/ibm-plex/*.woff2` are IBM Plex Sans and IBM Plex Mono, licensed under the
-SIL Open Font License 1.1. The licence text is at
-[`fonts/ibm-plex/OFL.txt`](fonts/ibm-plex/OFL.txt) and applies to the font files
-only, not to OpenPromptr itself, which is MIT-licensed.
-
-They are self-hosted rather than loaded from a font CDN. A remote font host
-observes every visitor's address and referrer on a page this project controls,
-which criterion `W07` forbids and criterion `Y02` would otherwise require this
-project to disclose.
diff --git a/docs/assets/core.tokens.css b/docs/assets/core.tokens.css
deleted file mode 100644
index dc9cb93..0000000
--- a/docs/assets/core.tokens.css
+++ /dev/null
@@ -1,275 +0,0 @@
-/* Vendored from trsdn/design-system (Instrument Workshop) v1.5.1. Source: core.tokens.css. Vendored on: 2026-09-17. Do not edit in place; re-vendor from a tag; see docs/assets/VENDORED.md. */
-/*
- * DO NOT EDIT — generated file
- * Source: tokens/core.tokens.json
- * Source SHA-256: c2c2e11413d4ea8a8a3f23ef80fdfebf50750231850e942f7d2555dcecbd6143
- * Generator: scripts/build-tokens.mjs@1.2.0
- * Lifecycle: Generated / non-normative
- * Decision: decisions/token-transform-architecture.md
- * Regenerate: node scripts/build-tokens.mjs
- */
-
-:root {
- color-scheme: light;
- --canvas: #d8d5ce;
- --surface-primary: #ece9e2;
- --surface-grouped: #c8c7c1;
- --surface-hover: #b9bbb5;
- --text-primary: #202522;
- --text-secondary: #5d625e;
- --border-essential: #656864;
- --rule-subtle: #9a9d98;
- --identity: #29483c;
- --identity-ink: #ffffff;
- --warning: #8a5400;
- --danger: #a4381a;
- --success: #315f4b;
- --focus: #111111;
- --surface-raised: #ece9e2;
- --surface-recessed: #d8d5ce;
- --surface-sunken: #d8d5ce;
- --surface-selected: #b9bbb5;
- --text-quiet: #5d625e;
- --text-attention: #8a5400;
- --text-critical: #a4381a;
- --border-subtle: #9a9d98;
- --border-quiet: #9a9d98;
- --status-critical: #a4381a;
- --status-caution: #8a5400;
- --status-affirmative: #315f4b;
- --focus-ring: #111111;
- --syntax-plain: #202522;
- --syntax-quiet: #5d625e;
- --syntax-keyword: #29483c;
- --syntax-string: #8a5400;
- --syntax-literal: #a4381a;
- --syntax-invalid: #a4381a;
- --syntax-added: #315f4b;
- --syntax-removed: #a4381a;
- --syntax-modified: #8a5400;
- --chart-categorical-1: #122f50;
- --chart-categorical-2: #643212;
- --chart-categorical-3: #24635c;
- --chart-categorical-4: #6e7a36;
- --chart-sequential-1: #a5c9ba;
- --chart-sequential-2: #7ea092;
- --chart-sequential-3: #58796b;
- --chart-sequential-4: #355448;
- --chart-sequential-5: #133226;
- --term-background: #ece9e2;
- --term-foreground: #202522;
- --term-cursor: #111111;
- --term-black: #1b201d;
- --term-bright-black: #3f4642;
- --term-red: #7a1800;
- --term-bright-red: #a63a1c;
- --term-green: #174633;
- --term-bright-green: #396753;
- --term-yellow: #5a3500;
- --term-bright-yellow: #885200;
- --term-blue: #243e63;
- --term-bright-blue: #485f86;
- --term-magenta: #6c2246;
- --term-bright-magenta: #924567;
- --term-cyan: #004452;
- --term-bright-cyan: #226678;
- --term-white: #4e534f;
- --term-bright-white: #6c716d;
-}
-
-@media (prefers-color-scheme: dark) {
- :root:not([data-theme="light"]) {
- color-scheme: dark;
- --canvas: #171b19;
- --surface-primary: #252a27;
- --surface-grouped: #343936;
- --surface-hover: #404641;
- --text-primary: #f0ede5;
- --text-secondary: #b8b6ae;
- --border-essential: #858a83;
- --rule-subtle: #555b56;
- --identity: #7fa38f;
- --identity-ink: #0d1a14;
- --warning: #ef9d36;
- --danger: #ee6b43;
- --success: #83b599;
- --focus: #ffffff;
- --surface-raised: #252a27;
- --surface-recessed: #171b19;
- --surface-sunken: #171b19;
- --surface-selected: #404641;
- --text-quiet: #b8b6ae;
- --text-attention: #ef9d36;
- --text-critical: #ee6b43;
- --border-subtle: #555b56;
- --border-quiet: #555b56;
- --status-critical: #ee6b43;
- --status-caution: #ef9d36;
- --status-affirmative: #83b599;
- --focus-ring: #ffffff;
- --syntax-plain: #f0ede5;
- --syntax-quiet: #b8b6ae;
- --syntax-keyword: #7fa38f;
- --syntax-string: #ef9d36;
- --syntax-literal: #ee6b43;
- --syntax-invalid: #ee6b43;
- --syntax-added: #83b599;
- --syntax-removed: #ee6b43;
- --syntax-modified: #ef9d36;
- --chart-categorical-1: #3878c3;
- --chart-categorical-2: #de7834;
- --chart-categorical-3: #4fc2b6;
- --chart-categorical-4: #c4d865;
- --chart-sequential-1: #2d4d3c;
- --chart-sequential-2: #4d6f5d;
- --chart-sequential-3: #709380;
- --chart-sequential-4: #94b9a4;
- --chart-sequential-5: #bae0cb;
- --term-background: #252a27;
- --term-foreground: #f0ede5;
- --term-cursor: #ffffff;
- --term-black: #101512;
- --term-bright-black: #495049;
- --term-red: #e46e4a;
- --term-bright-red: #ff9c7d;
- --term-green: #6b9b84;
- --term-bright-green: #8fc1a9;
- --term-yellow: #c28437;
- --term-bright-yellow: #eca85a;
- --term-blue: #7b91bb;
- --term-bright-blue: #a1b6e3;
- --term-magenta: #ca779a;
- --term-bright-magenta: #f29dc0;
- --term-cyan: #5b9aac;
- --term-bright-cyan: #81bfd2;
- --term-white: #9aa09b;
- --term-bright-white: #c6ccc7;
- }
-}
-
-html[data-theme="dark"] {
- color-scheme: dark;
- --canvas: #171b19;
- --surface-primary: #252a27;
- --surface-grouped: #343936;
- --surface-hover: #404641;
- --text-primary: #f0ede5;
- --text-secondary: #b8b6ae;
- --border-essential: #858a83;
- --rule-subtle: #555b56;
- --identity: #7fa38f;
- --identity-ink: #0d1a14;
- --warning: #ef9d36;
- --danger: #ee6b43;
- --success: #83b599;
- --focus: #ffffff;
- --surface-raised: #252a27;
- --surface-recessed: #171b19;
- --surface-sunken: #171b19;
- --surface-selected: #404641;
- --text-quiet: #b8b6ae;
- --text-attention: #ef9d36;
- --text-critical: #ee6b43;
- --border-subtle: #555b56;
- --border-quiet: #555b56;
- --status-critical: #ee6b43;
- --status-caution: #ef9d36;
- --status-affirmative: #83b599;
- --focus-ring: #ffffff;
- --syntax-plain: #f0ede5;
- --syntax-quiet: #b8b6ae;
- --syntax-keyword: #7fa38f;
- --syntax-string: #ef9d36;
- --syntax-literal: #ee6b43;
- --syntax-invalid: #ee6b43;
- --syntax-added: #83b599;
- --syntax-removed: #ee6b43;
- --syntax-modified: #ef9d36;
- --chart-categorical-1: #3878c3;
- --chart-categorical-2: #de7834;
- --chart-categorical-3: #4fc2b6;
- --chart-categorical-4: #c4d865;
- --chart-sequential-1: #2d4d3c;
- --chart-sequential-2: #4d6f5d;
- --chart-sequential-3: #709380;
- --chart-sequential-4: #94b9a4;
- --chart-sequential-5: #bae0cb;
- --term-background: #252a27;
- --term-foreground: #f0ede5;
- --term-cursor: #ffffff;
- --term-black: #101512;
- --term-bright-black: #495049;
- --term-red: #e46e4a;
- --term-bright-red: #ff9c7d;
- --term-green: #6b9b84;
- --term-bright-green: #8fc1a9;
- --term-yellow: #c28437;
- --term-bright-yellow: #eca85a;
- --term-blue: #7b91bb;
- --term-bright-blue: #a1b6e3;
- --term-magenta: #ca779a;
- --term-bright-magenta: #f29dc0;
- --term-cyan: #5b9aac;
- --term-bright-cyan: #81bfd2;
- --term-white: #9aa09b;
- --term-bright-white: #c6ccc7;
-}
-
-:root {
- --space-detail: 4px;
- --space-compact: 8px;
- --space-dense: 12px;
- --space-standard: 16px;
- --space-group: 24px;
- --space-section: 32px;
- --target-minimum: 24px;
- --target-compact-row: 32px;
- --target-standard-control: 40px;
- --target-touch-control: 44px;
- --target-pointer: 24px;
- --icon-size-inline: 16px;
- --icon-size-standard: 20px;
- --icon-size-prominent: 24px;
- --layout-page-inset-compact: 16px;
- --layout-page-inset-standard: 24px;
- --layout-page-inset-wide: 32px;
- --layout-work-width-maximum: 1440px;
- --edge-boundary-essential: 1px;
- --edge-state-emphasis: 3px;
- --edge-focus-width: 3px;
- --edge-focus-offset: 3px;
- --edge-focus-ring: 3px;
- --edge-radius-authored: 3px;
- --edge-clip-major: 10px;
- --edge-boundary-subtle: 1px;
- --edge-boundary-strong: 3px;
- --edge-signature: 3px;
- --edge-selection: 3px;
- --font-size-page-title: 26px;
- --font-size-section-title: 20px;
- --font-size-body: 16px;
- --font-size-body-compact: 15px;
- --font-size-label-dense: 13px;
- --font-size-caption: 12px;
- --font-size-heading: 20px;
- --font-size-display: 26px;
- --line-height-page-title: 1.2;
- --line-height-section-title: 1.25;
- --line-height-body: 1.5;
- --line-height-label-dense: 1.35;
- --font-weight-body: 400;
- --font-weight-emphasis: 500;
- --font-weight-title: 600;
- --font-weight-label-dense: 600;
- --letter-spacing-interface: 0em;
- --letter-spacing-eyebrow: 0.08em;
- --motion-duration-press-fast: 80ms;
- --motion-duration-press-standard: 160ms;
- --motion-duration-local-reveal: 200ms;
- --motion-duration-panel-transition: 240ms;
- --motion-duration-reduced: 100ms;
- --motion-easing-direct: cubic-bezier(0, 0, 0.58, 1);
- --font-interface: "IBM Plex Sans", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
- --font-data: "IBM Plex Mono", ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", monospace;
- --font-numeric: "IBM Plex Mono", ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", monospace;
-}
diff --git a/docs/assets/fonts/ibm-plex/IBMPlexMono-Regular.woff2 b/docs/assets/fonts/ibm-plex/IBMPlexMono-Regular.woff2
deleted file mode 100644
index 4297ee3..0000000
Binary files a/docs/assets/fonts/ibm-plex/IBMPlexMono-Regular.woff2 and /dev/null differ
diff --git a/docs/assets/fonts/ibm-plex/IBMPlexMono-SemiBold.woff2 b/docs/assets/fonts/ibm-plex/IBMPlexMono-SemiBold.woff2
deleted file mode 100644
index 86e2d90..0000000
Binary files a/docs/assets/fonts/ibm-plex/IBMPlexMono-SemiBold.woff2 and /dev/null differ
diff --git a/docs/assets/fonts/ibm-plex/IBMPlexSans-Medium.woff2 b/docs/assets/fonts/ibm-plex/IBMPlexSans-Medium.woff2
deleted file mode 100644
index b142a66..0000000
Binary files a/docs/assets/fonts/ibm-plex/IBMPlexSans-Medium.woff2 and /dev/null differ
diff --git a/docs/assets/fonts/ibm-plex/IBMPlexSans-Regular.woff2 b/docs/assets/fonts/ibm-plex/IBMPlexSans-Regular.woff2
deleted file mode 100644
index 231a1ad..0000000
Binary files a/docs/assets/fonts/ibm-plex/IBMPlexSans-Regular.woff2 and /dev/null differ
diff --git a/docs/assets/fonts/ibm-plex/IBMPlexSans-SemiBold.woff2 b/docs/assets/fonts/ibm-plex/IBMPlexSans-SemiBold.woff2
deleted file mode 100644
index b96a19c..0000000
Binary files a/docs/assets/fonts/ibm-plex/IBMPlexSans-SemiBold.woff2 and /dev/null differ
diff --git a/docs/assets/fonts/ibm-plex/OFL.txt b/docs/assets/fonts/ibm-plex/OFL.txt
deleted file mode 100644
index c35c4c6..0000000
--- a/docs/assets/fonts/ibm-plex/OFL.txt
+++ /dev/null
@@ -1,93 +0,0 @@
-Copyright © 2017 IBM Corp. with Reserved Font Name "Plex"
-
-This Font Software is licensed under the SIL Open Font License, Version 1.1.
-
-This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
-
-
------------------------------------------------------------
-SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
------------------------------------------------------------
-
-PREAMBLE
-The goals of the Open Font License (OFL) are to stimulate worldwide
-development of collaborative font projects, to support the font creation
-efforts of academic and linguistic communities, and to provide a free and
-open framework in which fonts may be shared and improved in partnership
-with others.
-
-The OFL allows the licensed fonts to be used, studied, modified and
-redistributed freely as long as they are not sold by themselves. The
-fonts, including any derivative works, can be bundled, embedded,
-redistributed and/or sold with any software provided that any reserved
-names are not used by derivative works. The fonts and derivatives,
-however, cannot be released under any other type of license. The
-requirement for fonts to remain under this license does not apply
-to any document created using the fonts or their derivatives.
-
-DEFINITIONS
-"Font Software" refers to the set of files released by the Copyright
-Holder(s) under this license and clearly marked as such. This may
-include source files, build scripts and documentation.
-
-"Reserved Font Name" refers to any names specified as such after the
-copyright statement(s).
-
-"Original Version" refers to the collection of Font Software components as
-distributed by the Copyright Holder(s).
-
-"Modified Version" refers to any derivative made by adding to, deleting,
-or substituting -- in part or in whole -- any of the components of the
-Original Version, by changing formats or by porting the Font Software to a
-new environment.
-
-"Author" refers to any designer, engineer, programmer, technical
-writer or other person who contributed to the Font Software.
-
-PERMISSION & CONDITIONS
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of the Font Software, to use, study, copy, merge, embed, modify,
-redistribute, and sell modified and unmodified copies of the Font
-Software, subject to the following conditions:
-
-1) Neither the Font Software nor any of its individual components,
-in Original or Modified Versions, may be sold by itself.
-
-2) Original or Modified Versions of the Font Software may be bundled,
-redistributed and/or sold with any software, provided that each copy
-contains the above copyright notice and this license. These can be
-included either as stand-alone text files, human-readable headers or
-in the appropriate machine-readable metadata fields within text or
-binary files as long as those fields can be easily viewed by the user.
-
-3) No Modified Version of the Font Software may use the Reserved Font
-Name(s) unless explicit written permission is granted by the corresponding
-Copyright Holder. This restriction only applies to the primary font name as
-presented to the users.
-
-4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
-Software shall not be used to promote, endorse or advertise any
-Modified Version, except to acknowledge the contribution(s) of the
-Copyright Holder(s) and the Author(s) or with their explicit written
-permission.
-
-5) The Font Software, modified or unmodified, in part or in whole,
-must be distributed entirely under this license, and must not be
-distributed under any other license. The requirement for fonts to
-remain under this license does not apply to any document created
-using the Font Software.
-
-TERMINATION
-This license becomes null and void if any of the above conditions are
-not met.
-
-DISCLAIMER
-THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
-OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
-COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
-DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
-OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/docs/assets/instrument-workshop-fonts.css b/docs/assets/instrument-workshop-fonts.css
deleted file mode 100644
index d46d097..0000000
--- a/docs/assets/instrument-workshop-fonts.css
+++ /dev/null
@@ -1,63 +0,0 @@
-/* Vendored from trsdn/design-system (Instrument Workshop) v1.5.1. Source: instrument-workshop-fonts.css. Vendored on: 2026-09-17. Do not edit in place; re-vendor from a tag; see docs/assets/VENDORED.md. */
-/*
- * Generated by scripts/build-font-stylesheet.mjs@1 — do not edit.
- * Source: src/web/styles/instrument-workshop-fonts.css
- * Regenerate: node scripts/build-font-stylesheet.mjs
- *
- * Identical to the source except that the font URLs are relative to assets/
- * rather than to an installed package, so anything inside assets/ can link
- * this sheet and get the accepted faces in a checkout, in the published
- * package, and on the portal alike.
- */
-/*
- * Instrument Workshop — bundled typefaces (optional layer)
- *
- * IBM Plex Sans + IBM Plex Mono, SIL Open Font License 1.1.
- * Source: @ibm/plex 6.4.1 (github.com/IBM/plex); license text ships alongside
- * the font files in fonts/ibm-plex/OFL.txt. Owner acceptance and the
- * verification evidence are recorded in foundations/design-language.md §5.1.
- *
- * Load this before the token stylesheet or not at all: the font-family tokens
- * fall back to the platform system stack when these faces are absent, so this
- * file is an enhancement, never a requirement.
- */
-
-@font-face {
- font-family: "IBM Plex Sans";
- src: url("fonts/ibm-plex/IBMPlexSans-Regular.woff2") format("woff2");
- font-weight: 400;
- font-style: normal;
- font-display: swap;
-}
-
-@font-face {
- font-family: "IBM Plex Sans";
- src: url("fonts/ibm-plex/IBMPlexSans-Medium.woff2") format("woff2");
- font-weight: 500;
- font-style: normal;
- font-display: swap;
-}
-
-@font-face {
- font-family: "IBM Plex Sans";
- src: url("fonts/ibm-plex/IBMPlexSans-SemiBold.woff2") format("woff2");
- font-weight: 600;
- font-style: normal;
- font-display: swap;
-}
-
-@font-face {
- font-family: "IBM Plex Mono";
- src: url("fonts/ibm-plex/IBMPlexMono-Regular.woff2") format("woff2");
- font-weight: 400;
- font-style: normal;
- font-display: swap;
-}
-
-@font-face {
- font-family: "IBM Plex Mono";
- src: url("fonts/ibm-plex/IBMPlexMono-SemiBold.woff2") format("woff2");
- font-weight: 600;
- font-style: normal;
- font-display: swap;
-}
diff --git a/docs/assets/instrument-workshop.css b/docs/assets/instrument-workshop.css
deleted file mode 100644
index 9d6011a..0000000
--- a/docs/assets/instrument-workshop.css
+++ /dev/null
@@ -1,2699 +0,0 @@
-/* Vendored from trsdn/design-system (Instrument Workshop) v1.5.1. Source: instrument-workshop.css. Vendored on: 2026-09-17. Do not edit in place; re-vendor from a tag; see docs/assets/VENDORED.md. */
-/*
- * Instrument Workshop — consumable component stylesheet
- *
- * Lifecycle: Candidate / consumable
- * Requires: tokens/generated/web/core.tokens.css (load first)
- * Source of truth for values: tokens/core.tokens.json
- * Foundations: foundations/design-language.md
- *
- * Usage:
- *
- *
- *
…
- *
- * This file styles real application markup. It adds no JavaScript, no build
- * step, and no framework. Every control is native HTML so platform behaviour,
- * keyboard support, and assistive technology semantics are preserved.
- *
- * Density: set data-density="compact | standard | comfortable" on any container.
- * Theme: set data-theme="dark" on (see core.tokens.css).
- *
- * Cascade: everything here lives in the `instrument-workshop` layer, so any
- * unlayered rule in a consuming app overrides these styles without specificity
- * escalation or !important.
- */
-
-@layer instrument-workshop {
-
-
-/* ==========================================================================
- 1. Base
- ========================================================================== */
-
-.iw-root {
- /* Web-only layout knobs; retune per app without forking the stylesheet.
- ch/rem measures have no cross-platform token equivalent. */
- --measure-prose: 66ch;
- --iw-sidebar-min: 200px;
- --iw-sidebar-max: 240px;
- --iw-metric-min: 14rem;
- --iw-avatar-size: 2rem;
- margin: 0;
- background: var(--canvas);
- color: var(--text-primary);
- font-family: var(--font-interface);
- font-size: var(--font-size-body);
- line-height: var(--line-height-body);
- font-weight: var(--font-weight-body);
- -webkit-text-size-adjust: 100%;
-}
-
-.iw-root *,
-.iw-root *::before,
-.iw-root *::after {
- box-sizing: border-box;
-}
-
-/* Density scale. Standard is the default for repeated work. */
-.iw-root,
-[data-density="standard"] {
- --iw-control-height: var(--target-standard-control);
- --iw-row-height: var(--target-standard-control);
- --iw-region-padding: var(--space-standard);
-}
-
-[data-density="compact"] {
- --iw-control-height: var(--target-compact-row);
- --iw-row-height: var(--target-compact-row);
- --iw-region-padding: var(--space-dense);
-}
-
-[data-density="comfortable"] {
- --iw-control-height: var(--target-touch-control);
- --iw-row-height: var(--target-touch-control);
- --iw-region-padding: var(--space-group);
-}
-
-/* Touch-capable input returns to comfortable targets regardless of density. */
-@media (pointer: coarse) {
- .iw-root,
- [data-density] {
- --iw-control-height: var(--target-touch-control);
- --iw-row-height: var(--target-touch-control);
- }
-}
-
-/* One focus indicator for every interactive surface. */
-.iw-root :focus-visible {
- outline: var(--edge-focus-width) solid var(--focus);
- outline-offset: var(--edge-focus-offset);
- border-radius: var(--edge-radius-authored);
-}
-
-.iw-root :focus:not(:focus-visible) {
- outline: none;
-}
-
-/* ==========================================================================
- 2. Typography roles (foundations section 5.2)
- ========================================================================== */
-
-.iw-page-title {
- margin: 0;
- font-size: var(--font-size-page-title);
- line-height: var(--line-height-page-title);
- font-weight: var(--font-weight-title);
- text-wrap: balance;
-}
-
-.iw-section-title {
- margin: 0;
- font-size: var(--font-size-section-title);
- line-height: var(--line-height-section-title);
- font-weight: var(--font-weight-title);
-}
-
-.iw-body {
- margin: 0;
- font-size: var(--font-size-body);
- line-height: var(--line-height-body);
-}
-
-.iw-body--compact {
- font-size: var(--font-size-body-compact);
-}
-
-.iw-secondary {
- color: var(--text-secondary);
-}
-
-.iw-caption {
- margin: 0;
- font-size: var(--font-size-caption);
- line-height: var(--line-height-label-dense);
- color: var(--text-secondary);
-}
-
-/*
- * Eyebrow — an indexed, uppercase label. Foundations limit uppercase to short
- * codes and eyebrows of 16 characters or fewer, with added tracking.
- */
-.iw-eyebrow {
- margin: 0;
- font-family: var(--font-data);
- font-size: var(--font-size-label-dense);
- line-height: var(--line-height-label-dense);
- font-weight: var(--font-weight-label-dense);
- letter-spacing: var(--letter-spacing-eyebrow);
- text-transform: uppercase;
- color: var(--text-secondary);
-}
-
-/* Signature: calibrated numerics. Tabular figures, stable alignment. */
-.iw-numeric {
- font-variant-numeric: tabular-nums;
- font-feature-settings: "tnum" 1;
- text-align: right;
- white-space: nowrap;
-}
-
-/* Codes, IDs, and exact values. Same optical size as surrounding text. */
-.iw-code {
- font-family: var(--font-data);
- font-size: 0.9375em;
- font-variant-numeric: tabular-nums;
-}
-
-/* ==========================================================================
- 3. Layout
- ========================================================================== */
-
-.iw-page {
- max-width: var(--layout-work-width-maximum);
- margin-inline: auto;
- padding-inline: var(--layout-page-inset-compact);
- padding-block: var(--space-group);
-}
-
-@media (min-width: 768px) {
- .iw-page {
- padding-inline: var(--layout-page-inset-standard);
- }
-}
-
-@media (min-width: 1200px) {
- .iw-page {
- padding-inline: var(--layout-page-inset-wide);
- }
-}
-
-/* Application shell: navigation column plus work column. */
-.iw-shell {
- display: grid;
- gap: var(--space-group);
- grid-template-columns: 1fr;
- align-items: start;
-}
-
-@media (min-width: 900px) {
- .iw-shell {
- grid-template-columns: minmax(var(--iw-sidebar-min, 200px), var(--iw-sidebar-max, 240px)) minmax(0, 1fr);
- }
-}
-
-.iw-page-header {
- display: flex;
- flex-wrap: wrap;
- gap: var(--space-standard);
- align-items: flex-end;
- justify-content: space-between;
- padding-block-end: var(--space-standard);
- border-block-end: var(--edge-boundary-essential) solid var(--border-essential);
-}
-
-.iw-page-header > div {
- display: grid;
- gap: var(--space-detail);
- min-width: 0;
-}
-
-.iw-stack {
- display: grid;
- gap: var(--space-standard);
-}
-
-.iw-stack--dense {
- gap: var(--space-dense);
-}
-
-.iw-stack--section {
- gap: var(--space-section);
-}
-
-.iw-row {
- display: flex;
- flex-wrap: wrap;
- gap: var(--space-compact);
- align-items: center;
-}
-
-.iw-spacer {
- flex: 1 1 auto;
-}
-
-/*
- * Signature: visible construction. Sections are separated by rules and shared
- * alignment rather than by giving every region its own floating card.
- */
-.iw-section {
- display: grid;
- gap: var(--space-dense);
- padding-block: var(--space-group);
- border-block-start: var(--edge-boundary-essential) solid var(--rule-subtle);
-}
-
-.iw-section:first-child {
- border-block-start: none;
- padding-block-start: 0;
-}
-
-/* ==========================================================================
- 4. Signatures
- ========================================================================== */
-
-/*
- * Signature: clipped geometry. A restrained clipped corner marks one major
- * authored region per view. Not for individual controls.
- */
-.iw-region {
- position: relative;
- align-content: start;
- padding: var(--iw-region-padding);
- background: var(--surface-primary);
- border: var(--edge-boundary-essential) solid var(--border-essential);
- border-radius: var(--edge-radius-authored);
-}
-
-.iw-region--authored {
- border-radius: 0;
- clip-path: polygon(
- 0 0,
- calc(100% - var(--edge-clip-major)) 0,
- 100% var(--edge-clip-major),
- 100% 100%,
- 0 100%
- );
-}
-
-/* The clip removes the border on the bevel, so restate the seam explicitly. */
-.iw-region--authored::after {
- content: "";
- position: absolute;
- inset-block-start: 0;
- inset-inline-end: 0;
- width: var(--edge-clip-major);
- height: var(--edge-clip-major);
- background: linear-gradient(
- to bottom left,
- var(--border-essential) 0 var(--edge-boundary-essential),
- transparent var(--edge-boundary-essential)
- );
- pointer-events: none;
-}
-
-/* Identity-led region: current position or branded authored area. */
-.iw-region--identity {
- border-inline-start: var(--edge-state-emphasis) solid var(--identity);
-}
-
-/*
- * Signature: calibrated indexing. A labelled scale tied to real quantity,
- * position, or sequence. Anti-rule: never decorative — each index must state a
- * real position, so it lives in markup as data-index rather than as a separate
- * decorative rail that can drift out of alignment with its rows.
- */
-.iw-index-list {
- list-style: none;
- margin: 0;
- padding: 0;
- display: grid;
- gap: var(--space-dense);
-}
-
-.iw-index-list > li {
- display: grid;
- grid-template-columns: auto minmax(0, 1fr);
- gap: var(--space-dense);
- align-items: baseline;
-}
-
-.iw-index-list > li::before {
- content: attr(data-index);
- align-self: stretch;
- padding-inline-end: var(--space-compact);
- border-inline-end: var(--edge-boundary-essential) solid var(--rule-subtle);
- font-family: var(--font-data);
- font-size: var(--font-size-caption);
- font-variant-numeric: tabular-nums;
- color: var(--text-secondary);
-}
-
-/* Current and completed positions are marked by weight and edge, not colour. */
-.iw-index-list > li[aria-current] {
- font-weight: var(--font-weight-title);
-}
-
-.iw-index-list > li[aria-current]::before {
- border-inline-end-color: var(--identity);
- border-inline-end-width: var(--edge-state-emphasis);
- color: var(--text-primary);
-}
-
-.iw-index-list > li[data-complete]::before {
- border-inline-end-color: var(--success);
- border-inline-end-width: var(--edge-state-emphasis);
-}
-
-/*
- * Signature: joined assemblies. Related controls share an outer boundary and
- * an aligned seam while remaining individually operable.
- */
-.iw-assembly {
- display: inline-flex;
- align-items: stretch;
- border: var(--edge-boundary-essential) solid var(--border-essential);
- border-radius: var(--edge-radius-authored);
- overflow: hidden;
- max-width: 100%;
-}
-
-.iw-assembly > * {
- border-radius: 0;
- border-block: none;
- border-inline-start: none;
- border-inline-end: var(--edge-boundary-essential) solid var(--border-essential);
- margin: 0;
-}
-
-.iw-assembly > *:last-child {
- border-inline-end: none;
-}
-
-/* Keep the focus ring readable above the shared seam. */
-.iw-assembly > *:focus-visible {
- outline-offset: calc(var(--edge-focus-offset) * -1);
- position: relative;
- z-index: 1;
-}
-
-/* ==========================================================================
- 5. Buttons
- ========================================================================== */
-
-.iw-button {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- gap: var(--space-compact);
- min-height: var(--iw-control-height);
- min-width: var(--target-minimum);
- padding-inline: var(--space-standard);
- border: var(--edge-boundary-essential) solid var(--border-essential);
- border-radius: var(--edge-radius-authored);
- background: var(--surface-primary);
- color: var(--text-primary);
- font: inherit;
- font-size: var(--font-size-body-compact);
- font-weight: var(--font-weight-emphasis);
- text-align: center;
- text-decoration: none;
- cursor: pointer;
- /* Signature: settled state change. Direct easing, no bounce or overshoot. */
- transition:
- background-color var(--motion-duration-press-fast) var(--motion-easing-direct),
- border-color var(--motion-duration-press-fast) var(--motion-easing-direct);
-}
-
-.iw-button:hover {
- background: var(--surface-hover);
-}
-
-.iw-button:active {
- background: var(--surface-grouped);
-}
-
-.iw-button[disabled],
-.iw-button[aria-disabled="true"] {
- cursor: not-allowed;
- opacity: 0.55;
-}
-
-/* One primary action leads a normal task region. */
-.iw-button--primary {
- background: var(--identity);
- border-color: var(--identity);
- color: var(--identity-ink);
- font-weight: var(--font-weight-title);
-}
-
-.iw-button--primary:hover,
-.iw-button--primary:active {
- background: var(--identity);
- border-color: var(--text-primary);
-}
-
-/*
- * Destructive actions carry a text label plus a colour role. Colour alone never
- * communicates the destructive meaning.
- */
-.iw-button--danger {
- color: var(--danger);
- border-color: var(--danger);
-}
-
-.iw-button--danger:hover {
- background: var(--surface-hover);
-}
-
-.iw-button--quiet {
- border-color: transparent;
- background: transparent;
-}
-
-.iw-button--quiet:hover {
- background: var(--surface-hover);
- border-color: var(--border-essential);
-}
-
-.iw-button--compact {
- min-height: var(--target-compact-row);
- padding-inline: var(--space-dense);
- font-size: var(--font-size-label-dense);
-}
-
-/* Toolbar of joined actions. */
-.iw-toolbar {
- display: flex;
- flex-wrap: wrap;
- gap: var(--space-compact);
- align-items: center;
- padding-block: var(--space-compact);
-}
-
-/* ==========================================================================
- 6. Fields and validation
- ========================================================================== */
-
-.iw-field {
- display: grid;
- gap: var(--space-detail);
- min-width: 0;
-}
-
-.iw-label {
- font-size: var(--font-size-label-dense);
- line-height: var(--line-height-label-dense);
- font-weight: var(--font-weight-label-dense);
-}
-
-.iw-input,
-.iw-select,
-.iw-textarea {
- min-height: var(--iw-control-height);
- width: 100%;
- padding: var(--space-compact) var(--space-dense);
- border: var(--edge-boundary-essential) solid var(--border-essential);
- border-radius: var(--edge-radius-authored);
- background: var(--surface-primary);
- color: var(--text-primary);
- font: inherit;
- font-size: var(--font-size-body-compact);
-}
-
-.iw-textarea {
- min-height: calc(var(--iw-control-height) * 2.5);
- line-height: var(--line-height-body);
- resize: vertical;
-}
-
-.iw-input::placeholder,
-.iw-textarea::placeholder {
- color: var(--text-secondary);
-}
-
-.iw-input:disabled,
-.iw-select:disabled,
-.iw-textarea:disabled {
- background: var(--surface-grouped);
- cursor: not-allowed;
-}
-
-/*
- * Invalid state uses a thickened edge plus a text message, never colour alone.
- * Pair with aria-invalid and aria-describedby on the control.
- */
-.iw-input[aria-invalid="true"],
-.iw-select[aria-invalid="true"],
-.iw-textarea[aria-invalid="true"] {
- border-color: var(--danger);
- border-inline-start-width: var(--edge-state-emphasis);
-}
-
-/* Helper text. Never carries errors or required instructions alone. */
-.iw-help {
- margin: 0;
- font-size: var(--font-size-caption);
- line-height: var(--line-height-label-dense);
- color: var(--text-secondary);
-}
-
-/* Inline validation message. Colour is on Surface 1 only (4.5:1 verified). */
-.iw-message {
- display: flex;
- gap: var(--space-detail);
- align-items: baseline;
- margin: 0;
- font-size: var(--font-size-label-dense);
- line-height: var(--line-height-label-dense);
- font-weight: var(--font-weight-emphasis);
-}
-
-.iw-message::before {
- font-family: var(--font-data);
- font-weight: var(--font-weight-title);
-}
-
-/*
- * Markers follow the state vocabulary in foundations/design-language.md §9.2,
- * the same one .iw-status uses: a warning is a triangle, an error an
- * exclamation, a success a check. Drawing a warning with the error's glyph
- * would leave colour as the only thing separating the two.
- */
-.iw-message--error {
- color: var(--danger);
-}
-
-.iw-message--error::before {
- content: "!";
-}
-
-.iw-message--warning {
- color: var(--warning);
-}
-
-.iw-message--warning::before {
- content: "\25B2";
-}
-
-.iw-message--success {
- color: var(--success);
-}
-
-.iw-message--success::before {
- content: "\2713";
-}
-
-/* Checkbox, radio, and their labels. */
-.iw-choice {
- display: flex;
- gap: var(--space-compact);
- align-items: center;
- min-height: var(--iw-control-height);
- cursor: pointer;
-}
-
-.iw-checkbox,
-.iw-radio {
- inline-size: var(--space-standard);
- block-size: var(--space-standard);
- accent-color: var(--identity);
- margin: 0;
- flex: none;
- cursor: pointer;
-}
-
-.iw-fieldset {
- margin: 0;
- padding: var(--iw-region-padding);
- border: var(--edge-boundary-essential) solid var(--border-essential);
- border-radius: var(--edge-radius-authored);
-}
-
-.iw-fieldset > legend {
- padding-inline: var(--space-compact);
- font-size: var(--font-size-label-dense);
- font-weight: var(--font-weight-label-dense);
-}
-
-/* C36 Radio group. One choice from a short, fully visible set. The group is a
- fieldset so the legend names the choice for assistive technology; the
- indicator aligns to the first line of a wrapped label rather than to the
- centre of a two-line block. */
-.iw-radio-group {
- margin: 0;
- padding: 0;
- border: 0;
- display: flex;
- flex-direction: column;
- gap: var(--space-compact);
-}
-
-.iw-radio-group > legend {
- padding: 0;
- margin-block-end: var(--space-compact);
- font-size: var(--font-size-label-dense);
- font-weight: var(--font-weight-label-dense);
-}
-
-.iw-radio-group .iw-choice {
- align-items: flex-start;
- min-height: 0;
- padding-block: calc(var(--space-compact) / 2);
-}
-
-.iw-radio-group .iw-radio {
- /* Centre the control on the first line of the label rather than on the
- whole label box, so a wrapped option stays aligned at 200% zoom. */
- margin-block-start: calc((1lh - var(--space-standard)) / 2);
-}
-
-.iw-radio-group[data-invalid="true"] > legend {
- color: var(--text-critical, currentColor);
-}
-
-/* Two-column form grid that reflows complete groups, never split fields. */
-.iw-form-grid {
- display: grid;
- gap: var(--space-standard);
- grid-template-columns: 1fr;
-}
-
-@media (min-width: 768px) {
- .iw-form-grid--two {
- grid-template-columns: repeat(2, minmax(0, 1fr));
- }
-}
-
-/* ==========================================================================
- 7. Table
- ========================================================================== */
-
-/*
- * The table may scroll internally when a stacked representation would destroy
- * comparison. A scrollable region must be reachable and announced, so mark it up
- * as .
- */
-.iw-table-wrap {
- overflow-x: auto;
- border: var(--edge-boundary-essential) solid var(--border-essential);
- border-radius: var(--edge-radius-authored);
-}
-
-.iw-table {
- width: 100%;
- border-collapse: collapse;
- font-size: var(--font-size-body-compact);
-}
-
-.iw-table caption {
- padding: var(--space-dense);
- text-align: start;
- font-size: var(--font-size-label-dense);
- font-weight: var(--font-weight-label-dense);
- color: var(--text-secondary);
-}
-
-.iw-table th,
-.iw-table td {
- padding: var(--space-compact) var(--space-dense);
- text-align: start;
- vertical-align: baseline;
- border-block-end: var(--edge-boundary-essential) solid var(--rule-subtle);
-}
-
-.iw-table thead th {
- height: var(--target-compact-row);
- background: var(--surface-grouped);
- border-block-end: var(--edge-boundary-essential) solid var(--border-essential);
- font-size: var(--font-size-label-dense);
- font-weight: var(--font-weight-label-dense);
- white-space: nowrap;
- position: sticky;
- top: 0;
- z-index: 1;
-}
-
-.iw-table tbody tr {
- height: var(--iw-row-height);
-}
-
-.iw-table tbody tr:hover {
- background: var(--surface-hover);
-}
-
-.iw-table tbody tr:last-child td {
- border-block-end: none;
-}
-
-/* Numeric and date columns keep stable alignment across rows. */
-.iw-table [data-numeric] {
- font-variant-numeric: tabular-nums;
- text-align: right;
- white-space: nowrap;
-}
-
-/*
- * Selected row: identity edge plus a checked control. The row is never
- * identified by background colour alone.
- */
-.iw-table tbody tr[aria-selected="true"] {
- background: var(--surface-grouped);
- box-shadow: inset var(--edge-state-emphasis) 0 0 0 var(--identity);
-}
-
-/* Sortable header button sits inside the th and keeps native semantics. */
-.iw-sort {
- display: inline-flex;
- align-items: center;
- gap: var(--space-detail);
- padding: var(--space-detail) 0;
- border: none;
- background: none;
- color: inherit;
- font: inherit;
- font-weight: var(--font-weight-label-dense);
- cursor: pointer;
-}
-
-.iw-sort::after {
- content: "\2195";
- font-family: var(--font-data);
- color: var(--text-secondary);
-}
-
-th[aria-sort="ascending"] .iw-sort::after {
- content: "\2191";
- color: var(--text-primary);
-}
-
-th[aria-sort="descending"] .iw-sort::after {
- content: "\2193";
- color: var(--text-primary);
-}
-
-/* ==========================================================================
- 8. Status, priority, and badges
- ========================================================================== */
-
-/*
- * State is carried by the text label. The marker adds a second, non-colour
- * channel so status survives greyscale and forced-colors.
- */
-.iw-status {
- display: inline-flex;
- align-items: baseline;
- gap: var(--space-detail);
- font-size: var(--font-size-label-dense);
- font-weight: var(--font-weight-label-dense);
- white-space: nowrap;
-}
-
-.iw-status::before {
- content: "\25A1";
- font-family: var(--font-data);
-}
-
-.iw-status[data-state="ready"]::before {
- content: "\25A0";
- color: var(--success);
-}
-
-.iw-status[data-state="in-progress"]::before {
- content: "\25D0";
- color: var(--identity);
-}
-
-.iw-status[data-state="at-risk"]::before {
- content: "\25B2";
- color: var(--warning);
-}
-
-.iw-status[data-state="blocked"]::before {
- content: "\2715";
- color: var(--danger);
-}
-
-.iw-status[data-state="complete"]::before {
- content: "\2713";
- color: var(--success);
-}
-
-/* Priority uses a monospaced code so P0…P3 align down a column. */
-.iw-priority {
- display: inline-flex;
- align-items: baseline;
- gap: var(--space-detail);
- font-family: var(--font-data);
- font-size: var(--font-size-label-dense);
- font-weight: var(--font-weight-label-dense);
- white-space: nowrap;
-}
-
-.iw-priority::before {
- content: "\2014\2014\2014";
- letter-spacing: -0.15em;
- color: var(--rule-subtle);
-}
-
-.iw-priority[data-priority="p0"]::before {
- content: "\2588\2588\2588";
- letter-spacing: 0;
- color: var(--danger);
-}
-
-.iw-priority[data-priority="p1"]::before {
- content: "\2588\2588\2014";
- letter-spacing: 0;
- color: var(--warning);
-}
-
-.iw-priority[data-priority="p2"]::before {
- content: "\2588\2014\2014";
- letter-spacing: 0;
- color: var(--text-secondary);
-}
-
-.iw-badge {
- display: inline-flex;
- align-items: center;
- gap: var(--space-detail);
- padding: 0 var(--space-compact);
- min-height: var(--target-minimum);
- border: var(--edge-boundary-essential) solid var(--border-essential);
- border-radius: var(--edge-radius-authored);
- background: var(--surface-grouped);
- font-size: var(--font-size-caption);
- font-weight: var(--font-weight-label-dense);
- white-space: nowrap;
-}
-
-.iw-badge--identity {
- border-color: var(--identity);
- border-inline-start-width: var(--edge-state-emphasis);
-}
-
-/* ==========================================================================
- 9. Callouts
- ========================================================================== */
-
-/*
- * Callouts sit on Surface 1 so the coloured title text keeps its verified
- * contrast ratio. The left edge and the title word carry the meaning together.
- */
-.iw-callout {
- display: grid;
- align-content: start;
- gap: var(--space-detail);
- padding: var(--space-dense) var(--space-standard);
- background: var(--surface-primary);
- border: var(--edge-boundary-essential) solid var(--border-essential);
- border-inline-start-width: var(--edge-state-emphasis);
- border-radius: var(--edge-radius-authored);
-}
-
-.iw-callout > p {
- margin: 0;
-}
-
-.iw-callout-title {
- margin: 0;
- font-size: var(--font-size-label-dense);
- line-height: var(--line-height-label-dense);
- font-weight: var(--font-weight-title);
-}
-
-.iw-callout--warning {
- border-inline-start-color: var(--warning);
-}
-
-.iw-callout--warning .iw-callout-title {
- color: var(--warning);
-}
-
-.iw-callout--danger {
- border-inline-start-color: var(--danger);
-}
-
-.iw-callout--danger .iw-callout-title {
- color: var(--danger);
-}
-
-.iw-callout--success {
- border-inline-start-color: var(--success);
-}
-
-.iw-callout--success .iw-callout-title {
- color: var(--success);
-}
-
-.iw-callout--identity {
- border-inline-start-color: var(--identity);
-}
-
-/* ==========================================================================
- 10. Navigation
- ========================================================================== */
-
-.iw-nav {
- display: grid;
- gap: var(--space-detail);
-}
-
-.iw-nav ul {
- list-style: none;
- margin: 0;
- padding: 0;
- display: grid;
- gap: var(--space-detail);
-}
-
-.iw-nav a {
- display: flex;
- align-items: center;
- min-height: var(--iw-control-height);
- padding: var(--space-compact) var(--space-dense);
- border-inline-start: var(--edge-state-emphasis) solid transparent;
- color: var(--text-primary);
- text-decoration: none;
-}
-
-.iw-nav a:hover {
- background: var(--surface-hover);
-}
-
-/* Current position: identity edge plus a weight change, never colour alone. */
-.iw-nav a[aria-current] {
- border-inline-start-color: var(--identity);
- background: var(--surface-grouped);
- font-weight: var(--font-weight-title);
-}
-
-.iw-breadcrumb {
- font-size: var(--font-size-label-dense);
- color: var(--text-secondary);
-}
-
-.iw-breadcrumb ol {
- list-style: none;
- display: flex;
- flex-wrap: wrap;
- gap: var(--space-compact);
- margin: 0;
- padding: 0;
-}
-
-.iw-breadcrumb li + li::before {
- content: "/";
- margin-inline-end: var(--space-compact);
- color: var(--rule-subtle);
-}
-
-.iw-breadcrumb a {
- color: inherit;
-}
-
-.iw-breadcrumb [aria-current] {
- color: var(--text-primary);
- font-weight: var(--font-weight-emphasis);
-}
-
-/* Tabs. Use with role="tablist" and native buttons. */
-.iw-tabs {
- display: flex;
- flex-wrap: wrap;
- gap: 0;
- border-block-end: var(--edge-boundary-essential) solid var(--border-essential);
-}
-
-.iw-tab {
- min-height: var(--iw-control-height);
- padding: var(--space-compact) var(--space-standard);
- border: none;
- border-block-end: var(--edge-state-emphasis) solid transparent;
- background: none;
- color: var(--text-secondary);
- font: inherit;
- font-size: var(--font-size-body-compact);
- font-weight: var(--font-weight-emphasis);
- cursor: pointer;
-}
-
-.iw-tab:hover {
- color: var(--text-primary);
- background: var(--surface-hover);
-}
-
-.iw-tab[aria-selected="true"] {
- color: var(--text-primary);
- border-block-end-color: var(--identity);
- font-weight: var(--font-weight-title);
-}
-
-/* ==========================================================================
- 11. Dialog
- ========================================================================== */
-
-.iw-dialog {
- padding: 0;
- border: var(--edge-boundary-essential) solid var(--border-essential);
- border-radius: var(--edge-radius-authored);
- background: var(--surface-primary);
- color: var(--text-primary);
- max-width: min(560px, calc(100vw - var(--space-section)));
- font-family: var(--font-interface);
-}
-
-.iw-dialog::backdrop {
- background: rgb(0 0 0 / 0.55);
-}
-
-.iw-dialog-header,
-.iw-dialog-footer {
- padding: var(--space-standard);
-}
-
-.iw-dialog-header {
- border-block-end: var(--edge-boundary-essential) solid var(--rule-subtle);
-}
-
-.iw-dialog-body {
- padding: var(--space-standard);
- display: grid;
- gap: var(--space-standard);
-}
-
-.iw-dialog-footer {
- display: flex;
- flex-wrap: wrap;
- gap: var(--space-compact);
- justify-content: flex-end;
- border-block-start: var(--edge-boundary-essential) solid var(--rule-subtle);
-}
-
-/* ==========================================================================
- 12. Feedback and progression
- ========================================================================== */
-
-/* Live status region. Pair with role="status" and aria-live="polite". */
-.iw-live {
- margin: 0;
- padding: var(--space-compact) var(--space-dense);
- background: var(--surface-grouped);
- border-inline-start: var(--edge-state-emphasis) solid var(--identity);
- border-radius: var(--edge-radius-authored);
- font-size: var(--font-size-body-compact);
-}
-
-.iw-empty {
- display: grid;
- gap: var(--space-compact);
- justify-items: start;
- padding: var(--space-section) var(--space-standard);
- border: var(--edge-boundary-essential) dashed var(--border-essential);
- border-radius: var(--edge-radius-authored);
-}
-
-/* Bulk action bar for a filtered result. */
-.iw-bulk-bar {
- display: flex;
- flex-wrap: wrap;
- gap: var(--space-compact);
- align-items: center;
- padding: var(--space-compact) var(--space-dense);
- background: var(--surface-grouped);
- border: var(--edge-boundary-essential) solid var(--border-essential);
- border-radius: var(--edge-radius-authored);
- font-size: var(--font-size-body-compact);
-}
-
-/*
- * Signature: calibrated indexing applied to progression. Each step shows a real
- * position in a real sequence.
- */
-.iw-steps {
- list-style: none;
- display: flex;
- flex-wrap: wrap;
- gap: var(--space-standard);
- margin: 0;
- padding: 0;
- font-size: var(--font-size-label-dense);
-}
-
-.iw-steps li {
- display: flex;
- align-items: baseline;
- gap: var(--space-compact);
- padding-block-end: var(--space-compact);
- border-block-end: var(--edge-state-emphasis) solid var(--rule-subtle);
- color: var(--text-secondary);
-}
-
-.iw-steps li::before {
- content: attr(data-step);
- font-family: var(--font-data);
- font-variant-numeric: tabular-nums;
-}
-
-.iw-steps li[aria-current] {
- color: var(--text-primary);
- border-block-end-color: var(--identity);
- font-weight: var(--font-weight-title);
-}
-
-.iw-steps li[data-complete] {
- color: var(--text-primary);
- border-block-end-color: var(--success);
-}
-
-/* Determinate meter tied to a stated quantity. */
-.iw-meter {
- display: grid;
- gap: var(--space-detail);
-}
-
-.iw-meter-track {
- height: var(--space-compact);
- background: var(--surface-grouped);
- border: var(--edge-boundary-essential) solid var(--border-essential);
- border-radius: var(--edge-radius-authored);
- overflow: hidden;
-}
-
-.iw-meter-fill {
- height: 100%;
- background: var(--identity);
-}
-
-/* ==========================================================================
- 13. Catalog components (C36-C79)
- ==========================================================================
- The classes below cover the components admitted on platform convention.
- Each one styles a native control or a plain container around one: the
- behaviour stays with the platform, only the appearance is ours.
- ========================================================================== */
-
-/* C37 Divider with an optional label. A rule that says what it separates. */
-.iw-divider {
- display: grid;
- grid-template-columns: auto 1fr;
- align-items: center;
- gap: var(--space-compact);
- margin-block: var(--space-standard);
- font-size: var(--font-size-label-dense);
- color: var(--text-secondary);
-}
-
-.iw-divider::after {
- content: "";
- height: var(--edge-boundary-essential);
- background: var(--rule-subtle);
-}
-
-/* C38 Card. A surface that carries one subject and its actions. */
-.iw-card {
- display: grid;
- gap: var(--space-compact);
- padding: var(--space-standard);
- background: var(--surface-primary);
- border: var(--edge-boundary-essential) solid var(--border-essential);
- border-radius: var(--edge-radius-authored);
-}
-
-.iw-card-title {
- margin: 0;
- font-size: var(--font-size-section-title);
- font-weight: var(--font-weight-title);
-}
-
-/* C39 Avatar. Initials by default; an image only when one exists. */
-.iw-avatar {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- inline-size: var(--iw-avatar-size, 2rem);
- block-size: var(--iw-avatar-size, 2rem);
- border-radius: 50%;
- border: var(--edge-boundary-essential) solid var(--border-essential);
- background: var(--surface-grouped);
- font-size: var(--font-size-label-dense);
- font-weight: var(--font-weight-title);
-}
-
-.iw-identity-row {
- display: flex;
- align-items: center;
- gap: var(--space-compact);
-}
-
-/* C40 Skeleton. A placeholder with the shape of the content it waits for. */
-.iw-skeleton {
- display: block;
- block-size: var(--space-standard);
- background: var(--surface-grouped);
- border: var(--edge-boundary-essential) solid var(--rule-subtle);
- border-radius: var(--edge-radius-authored);
-}
-
-.iw-skeleton + .iw-skeleton {
- margin-block-start: var(--space-compact);
-}
-
-/* C41 Tag. A user-applied label, removable where the user applied it. */
-.iw-tag {
- display: inline-flex;
- align-items: center;
- gap: var(--space-detail);
- padding: 0 var(--space-compact);
- border: var(--edge-boundary-essential) solid var(--border-essential);
- border-radius: var(--edge-radius-authored);
- background: var(--surface-grouped);
- font-size: var(--font-size-label-dense);
-}
-
-/* C42 Tooltip and C66 shortcut hint. Supporting text, never the only route. */
-.iw-kbd {
- font-family: var(--font-data);
- font-size: var(--font-size-label-dense);
- padding: 0 var(--space-detail);
- border: var(--edge-boundary-essential) solid var(--border-essential);
- border-radius: var(--edge-radius-authored);
- background: var(--surface-grouped);
-}
-
-.iw-shortcut-row {
- display: grid;
- grid-template-columns: minmax(0, 1fr) auto;
- gap: var(--space-compact);
- align-items: baseline;
-}
-
-/* C67 Icon. Sized from the icon scale rather than from the text around it, and
- coloured by inheritance so it follows every contrast decision already made for
- that text. The inline size is a floor: dense contexts keep it instead of
- shrinking, because the drawings stop resolving before the type does. */
-.iw-icon {
- inline-size: var(--icon-size-inline);
- block-size: var(--icon-size-inline);
- vertical-align: -0.125em;
- flex: none;
-}
-
-.iw-icon--standard {
- inline-size: var(--icon-size-standard);
- block-size: var(--icon-size-standard);
-}
-
-.iw-icon--prominent {
- inline-size: var(--icon-size-prominent);
- block-size: var(--icon-size-prominent);
-}
-
-/* C68 Image or thumbnail. The frame holds its ratio before the image arrives. */
-.iw-figure {
- margin: 0;
- display: grid;
- gap: var(--space-detail);
- max-inline-size: 30rem;
-}
-
-.iw-figure-frame {
- aspect-ratio: 16 / 9;
- border: var(--edge-boundary-essential) solid var(--border-essential);
- background: var(--surface-grouped);
- overflow: hidden;
-}
-
-.iw-figure-frame > img {
- inline-size: 100%;
- block-size: 100%;
- object-fit: cover;
- display: block;
-}
-
-/* C69 Count badge. The number is decoration here; the host carries it in words. */
-.iw-count-host {
- display: inline-flex;
- align-items: center;
- gap: var(--space-detail);
-}
-
-.iw-count {
- border: var(--edge-boundary-essential) solid var(--border-essential);
- border-radius: 1em;
- padding: 0 0.4em;
- font-family: var(--font-data);
- font-size: var(--font-size-label-dense);
-}
-
-/* C70 Metric tile. One quantity, its period, and how it moved. */
-.iw-metrics {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--iw-metric-min, 14rem)), 1fr));
- gap: var(--space-compact);
-}
-
-.iw-metric {
- margin: 0;
- display: grid;
- gap: var(--space-detail);
- padding: var(--space-compact);
- border: var(--edge-boundary-essential) solid var(--border-essential);
- min-inline-size: 0;
-}
-
-.iw-metric-label {
- color: var(--text-secondary);
- font-size: var(--font-size-label-dense);
-}
-
-.iw-metric-value {
- margin: 0;
- font-family: var(--font-data);
- font-size: var(--font-size-heading);
-}
-
-.iw-metric-period {
- margin: 0;
- color: var(--text-secondary);
- font-size: var(--font-size-label-dense);
-}
-
-/* C71 Sparkline. One ink, no axes, and the numbers live in the text beside it. */
-.iw-sparkline {
- inline-size: 100%;
- block-size: 2rem;
- color: var(--text-primary);
-}
-
-/* C72 Bar comparison. A table of labelled numbers; the bars are length only. */
-.iw-comparison {
- inline-size: 100%;
- border-collapse: collapse;
-}
-
-.iw-comparison caption {
- text-align: start;
- color: var(--text-secondary);
- padding-block-end: var(--space-detail);
-}
-
-.iw-comparison th,
-.iw-comparison td {
- padding: var(--space-detail) var(--space-compact);
- text-align: start;
- font-weight: inherit;
-}
-
-.iw-comparison td {
- font-family: var(--font-data);
-}
-
-.iw-bar {
- display: block;
- block-size: 0.5rem;
- inline-size: var(--iw-bar-length, 0%);
- background: var(--text-primary);
- margin-block-end: var(--space-detail);
-}
-
-/* C43 Slider. The native range plus the value it stands for, as text. */
-.iw-range {
- inline-size: 100%;
- max-inline-size: 22rem;
- accent-color: var(--identity);
-}
-
-/* C47/C48 Combo box and multi-select. Native list semantics, our spacing. */
-.iw-option-list {
- list-style: none;
- margin: 0;
- padding: var(--space-compact);
- display: grid;
- gap: var(--space-compact);
- border: var(--edge-boundary-essential) solid var(--border-essential);
- border-radius: var(--edge-radius-authored);
- background: var(--surface-primary);
-}
-
-/* C50 Segmented control. One row of radios that behaves as one control. */
-.iw-segmented {
- display: inline-flex;
- border: var(--edge-boundary-essential) solid var(--border-essential);
- border-radius: var(--edge-radius-authored);
- overflow: hidden;
-}
-
-.iw-segmented label {
- padding: var(--space-compact) var(--space-dense);
- font-size: var(--font-size-label-dense);
- border-inline-start: var(--edge-boundary-essential) solid var(--border-essential);
-}
-
-.iw-segmented label:first-of-type {
- border-inline-start: 0;
-}
-
-.iw-segmented input {
- position: absolute;
- opacity: 0;
- pointer-events: none;
-}
-
-.iw-segmented label:has(input:checked) {
- background: var(--identity);
- color: var(--identity-ink);
- font-weight: var(--font-weight-title);
-}
-
-.iw-segmented label:has(input:focus-visible) {
- outline: var(--edge-focus-ring) solid var(--focus-ring);
- outline-offset: calc(var(--edge-focus-ring) * -1);
-}
-
-/* C52 Tree view. Structure carried by indentation and expanded state. */
-.iw-tree,
-.iw-tree ul {
- list-style: none;
- margin: 0;
- padding: 0;
-}
-
-.iw-tree ul {
- padding-inline-start: var(--space-standard);
- border-inline-start: var(--edge-boundary-essential) solid var(--rule-subtle);
- margin-inline-start: var(--space-compact);
-}
-
-.iw-tree [role="treeitem"] > span {
- display: inline-block;
- padding: var(--space-detail) 0;
-}
-
-/* C55/C56 Progress and activity. Every wait names what it is waiting for. */
-.iw-progress {
- inline-size: 100%;
- max-inline-size: 22rem;
- block-size: var(--space-compact);
- accent-color: var(--identity);
-}
-
-.iw-activity {
- display: flex;
- align-items: center;
- gap: var(--space-compact);
-}
-
-.iw-activity-mark {
- inline-size: 1rem;
- block-size: 1rem;
- border: var(--edge-state-emphasis) solid currentColor;
- border-right-color: transparent;
- border-radius: 50%;
- animation: iw-spin 1s linear infinite;
-}
-
-@keyframes iw-spin {
- to {
- transform: rotate(360deg);
- }
-}
-
-@media (prefers-reduced-motion: reduce) {
- .iw-activity-mark {
- animation: none;
- border-right-color: currentColor;
- }
-}
-
-/* C57/C59/C60 Popover, drawer, and coach mark: three surfaces, one edge. */
-.iw-surface {
- padding: var(--space-dense);
- background: var(--surface-primary);
- border: var(--edge-boundary-essential) solid var(--border-essential);
- border-radius: var(--edge-radius-authored);
- display: grid;
- gap: var(--space-compact);
- justify-items: start;
-}
-
-.iw-surface--coach {
- border-inline-start-width: var(--edge-state-emphasis);
- border-inline-start-color: var(--identity);
-}
-
-/* C61 Accordion. Sibling disclosures presented as one list of headings. */
-.iw-accordion {
- border: var(--edge-boundary-essential) solid var(--border-essential);
- border-radius: var(--edge-radius-authored);
- overflow: hidden;
-}
-
-.iw-accordion-heading {
- margin: 0;
- font-size: inherit;
-}
-
-.iw-accordion-trigger {
- display: grid;
- grid-template-columns: minmax(0, 1fr) auto;
- gap: var(--space-compact);
- inline-size: 100%;
- text-align: start;
- padding: var(--space-dense);
- background: none;
- border: 0;
- border-block-end: var(--edge-boundary-essential) solid var(--rule-subtle);
- color: inherit;
- font: inherit;
- font-weight: var(--font-weight-title);
- cursor: pointer;
-}
-
-.iw-accordion-panel {
- padding: var(--space-dense);
- border-block-end: var(--edge-boundary-essential) solid var(--rule-subtle);
-}
-
-/* C62 Context menu. The same actions the visible control already offers. */
-.iw-menu {
- list-style: none;
- margin: 0;
- padding: var(--space-compact);
- display: grid;
- gap: var(--space-detail);
- background: var(--surface-primary);
- border: var(--edge-boundary-essential) solid var(--border-essential);
- border-radius: var(--edge-radius-authored);
- min-inline-size: 12rem;
-}
-
-.iw-menu [role="menuitem"] {
- display: block;
- inline-size: 100%;
- text-align: start;
- padding: var(--space-compact);
- background: none;
- border: 0;
- color: inherit;
- font: inherit;
- cursor: pointer;
-}
-
-.iw-menu [role="menuitem"][aria-disabled="true"] {
- color: var(--text-secondary);
- cursor: default;
-}
-
-.iw-menu [role="menuitem"]:hover:not([aria-disabled="true"]) {
- background: var(--surface-grouped);
-}
-
-/* C63 Split view. A divider that is a control, not a decoration. */
-.iw-split {
- display: grid;
- grid-template-columns: minmax(0, 2fr) auto minmax(0, 3fr);
- gap: var(--space-dense);
- border: var(--edge-boundary-essential) solid var(--border-essential);
- border-radius: var(--edge-radius-authored);
- padding: var(--space-dense);
-}
-
-.iw-split-divider {
- inline-size: var(--edge-state-emphasis);
- background: var(--border-essential);
- border: 0;
- padding: 0;
- cursor: col-resize;
-}
-
-@media (max-width: 47.9375rem) {
- .iw-split {
- grid-template-columns: minmax(0, 1fr);
- }
-
- .iw-split-divider {
- display: none;
- }
-}
-
-/* C65 Colour picker. The swatch is decorative; the value is the text. */
-.iw-swatch {
- inline-size: 1.5rem;
- block-size: 1.5rem;
- border: var(--edge-boundary-essential) solid var(--border-essential);
- border-radius: var(--edge-radius-authored);
-}
-
-/* ==========================================================================
- 14. Utilities
- ========================================================================== */
-
-.iw-visually-hidden {
- position: absolute;
- width: 1px;
- height: 1px;
- margin: -1px;
- padding: 0;
- overflow: hidden;
- clip-path: inset(50%);
- white-space: nowrap;
- border: 0;
-}
-
-.iw-skip-link {
- position: absolute;
- inset-inline-start: var(--space-standard);
- inset-block-start: calc(var(--space-standard) * -4);
- z-index: 10;
- padding: var(--space-compact) var(--space-standard);
- background: var(--surface-primary);
- border: var(--edge-boundary-essential) solid var(--border-essential);
- color: var(--text-primary);
-}
-
-.iw-skip-link:focus {
- inset-block-start: var(--space-standard);
-}
-
-.iw-rule {
- border: none;
- border-block-start: var(--edge-boundary-essential) solid var(--rule-subtle);
- margin-block: var(--space-standard);
-}
-
-/* A field that spans every column of an iw-form-grid. */
-.iw-field--full {
- grid-column: 1 / -1;
-}
-
-/* ==========================================================================
- 15. Environment adaptation
- ========================================================================== */
-
-@media (prefers-reduced-motion: reduce) {
- .iw-root *,
- .iw-root *::before,
- .iw-root *::after {
- transition-duration: var(--motion-duration-reduced) !important;
- animation-duration: var(--motion-duration-reduced) !important;
- scroll-behavior: auto !important;
- }
-}
-
-/*
- * Forced colors: hand every colour decision back to the user's palette and keep
- * the non-colour channels (markers, edges, weight) doing the work.
- */
-/* --------------------------------------------------------------------------
- C73-C79 Commands. Dialog, toggle button, icon button, button group, split
- button, menu bar, and inline message. Each one wraps a native control; the
- modality, the pressed state, and the menu semantics stay with the platform.
- -------------------------------------------------------------------------- */
-
-/* C73 Dialog. `