Files
shd.build/docs/DESIGN_SYSTEM.md
T

636 lines
38 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SHD.build Design System
This document defines the visual language for SHD.build. New pages should feel like part of the same tactical data network as the admin dashboard, while public pages may use more space and larger editorial typography.
## Design principles
1. **Tactical, not military cosplay.** Use operational language, compact information density, restrained status indicators, and precise alignment. Avoid camouflage, distressed textures, or decorative weapon imagery in utility interfaces.
2. **Data first.** Hierarchy comes from grouping, typography, borders, and spacing. Admin tools should resemble a dependable control surface rather than a collection of marketing cards.
3. **Orange means action.** SHD orange identifies primary actions, active navigation, focus, and important values. It should not cover large areas.
4. **State is always visible.** Loading, disabled, active, archived, configured, error, and success states need both visual and textual indicators.
5. **Square and engineered.** Panels and controls use square corners, fine borders, tight spacing, and deliberate grid alignment.
6. **Links use interface feedback, not underlines.** Links do not use native text
underlines. Communicate hover and focus through SHD accent color, borders,
brightness, and the required focus-visible outline.
## Tokens
The canonical tokens live in `src/app.css` under `:root`.
| Purpose | Token | Value |
| --- | --- | --- |
| Page background | `--shd-bg` | `#0a0c0d` |
| Base surface | `--shd-surface` | `#111415` |
| Raised surface | `--shd-surface-raised` | `#141718` |
| Primary border | `--shd-border` | `#303536` |
| Main text | `--shd-text` | `#ecebe5` |
| Muted text | `--shd-text-muted` | `#858b8d` |
| SHD action orange | `--shd-orange` | `#f6a821` |
| Adaptive display scale | `--shd-display-scale` | `1` by default; stepped on high-resolution desktops |
### High-resolution display scaling
The application uses restrained, stepped interface scaling when the effective
CSS viewport is substantially wider than a conventional desktop. At 2200px the
complete interface scales to 115%, at 2800px to 130%, and at 3400px to 150%.
This preserves the established relationship between typography, controls,
tables, spacing, hit targets, and fixed-position surfaces instead of enlarging
text alone.
Use the shared `--shd-display-scale` token and the root-level `zoom` treatment;
do not add module-specific 4K font-size overrides. Responsive layouts below
2200px remain unchanged. Browser zoom and operating-system display scaling still
remain available to users and naturally change the effective CSS viewport.
High-resolution scaling must not introduce horizontal overflow, clipped fixed
surfaces, or a different semantic hierarchy. Test the standard desktop layout
and each affected wide breakpoint after changing this policy.
| Success | `--shd-success` | `#75c08c` |
| Destructive/error | `--shd-danger` | `#df8069` |
| Informational/defensive | `--shd-info` | `#70b9d6` |
Use the spacing tokens for new components. Prefer `8px`, `12px`, and `20px` gaps. Dashboard controls use the shared `40px` height when practical.
## Typography
- The current UI stack is `Arial, Helvetica, sans-serif`.
- Page and module headings are uppercase, heavy, and tightly spaced.
- Eyebrows and table labels use 7–10px text with 1–2px letter spacing.
- Body and form text should normally remain between 9–12px in dashboards.
- Public/editorial copy may use Georgia for a restrained field-manual character.
- Never use low-contrast tiny text for information required to complete a task.
## Layout patterns
### Global mobile navigation
At viewports up to 900px, replace the hidden desktop link rail and account
controls with a clearly labeled square `MENU` control in the shared site
header. Activating it opens a right-side SHD navigation panel over a dismissible
backdrop. The panel includes Home, Discover, Builder, Guides, Sign In or My
Profile, and ISAC when authorized; authenticated agents also receive identity
state and Sign Out inside the panel.
Use numbered full-width navigation rows, explicit active-route text styling,
orange action indicators, and minimum 44px interaction targets. Opening moves
keyboard focus to the first route. Escape, backdrop activation, route changes,
and the header Close control dismiss the panel. The toggle exposes
`aria-expanded` and `aria-controls`, the panel has a distinct navigation label,
and reduced-motion preferences remove icon transitions. Do not make mobile
users rely on the logo or desktop-only account controls to reach core routes.
On phone-sized viewports up to 700px, ISAC module toolbars stack their action
area beneath the module title. A single Add action spans the available width;
multiple creation actions share an equal responsive grid. These controls use a
minimum 48px height, centered labels, and the standard pressed, focus-visible,
pending, and disabled treatments. Do not leave desktop-sized Add buttons
squeezed beside long module headings on mobile.
### Public pages
- Maximum content width: approximately 1400–1640px.
- Larger headings and more generous vertical rhythm are appropriate.
- Preserve the grid background and orange accents.
- Catalogue and editorial pages use `catalogue-hero` for an angular introductory
panel and may pair it with a compact operational control bar.
- Community build cards retain the colored top rule, abstract loadout artwork,
concise tags, agent attribution, and a full-width terminal action.
### Agent and authentication surfaces
- Account pages should read as an agent dossier: identity and access at the top,
activity metrics beside it, archives in the primary column, and security
controls in a narrower console column.
- Dense account consoles use a tabbed control surface for profile, credentials,
linked identities, and account lifecycle actions. Only one panel is shown at
a time; validation failures reopen the panel containing the failed action.
Closely related mutually exclusive workflows, such as selecting a preset
portrait or uploading a custom portrait, use a compact secondary tab row.
Tabs retain native button semantics plus tablist, tab, and tabpanel roles,
textual selected state, keyboard focus, and pressed feedback.
- Account Access uses a secondary method navigation for passkeys, verified
email, local password fallback, and linked identity providers. Each tab shows
a compact configured-method count and routes failed actions back to the
relevant panel. External identity connections live inside Access rather than
competing with it as a top-level account domain.
- Future external providers may appear as non-interactive planned rows so the
intended identity architecture is visible before credentials are configured.
Placeholders must be visually subdued, explicitly labeled `PLANNED`, and must
not imitate enabled buttons. Provider-compliant assets and controls replace
these rows only when the corresponding OAuth application is implemented.
- Provider unlinking does not assume that a password exists. The unlink control
is the provider card’s `LINKED` status badge. Hover and keyboard focus turn it
red and replace the label with `UNLINK`; activation replaces the full card
surface with an explicit Cancel / Confirm Unlink decision. Confirmation uses
the square SHD primary action with the orange action accent, while Cancel
remains a dark outlined secondary control. The authenticated
session plus this deliberate second action authorizes the request; the shared
server-side last-method guard remains authoritative. Future provider cards
reuse this pattern rather than adding provider-specific credential prompts.
- Authentication pages use a split frame: contextual SHD network information on
the left and the actionable secure-access console on the right.
- OAuth providers appear as connection nodes with a recognizable provider color;
SHD orange remains reserved for the primary local action and navigation.
- Authentication prioritizes passkeys, followed by one-time email magic links.
Discord remains a prominent provider option, while username/password is an
explicitly labeled optional fallback in a collapsed control. Passkey controls
name the platform interaction rather than exposing WebAuthn terminology.
- Verified email identities and registered passkeys appear as compact method
rows in Account Access. Every method displays its verification or device state,
registration date where useful, and protected removal behavior that prevents
an agent from deleting their last usable sign-in method.
- Local username and password are one optional authentication method, separate
from the public display name and the immutable internal account identifier.
Agents may remove both local credentials together after adding another method,
and may restore them later with a new unique login username and password.
- The “at least one sign-in method” rule is a server-side invariant shared by
self-service and ISAC actions. Passkeys, verified magic-link email, Discord,
and a complete local username/password pair each count as usable methods.
Controls may disable unsafe removal for clarity, but server validation remains
authoritative. Intentional soft account deletion is the sole exception.
- Linked identity nodes show provider display name, account handle or stable ID,
and an explicit textual `LINKED` state. Unlink controls sit beneath the node,
require credential confirmation, and remain disabled with an explanation when
unlinking would remove the user's only sign-in method.
- ISAC user dossiers reuse the same linked-identity node. Administrative
unlinking requires a scoped identity-management capability, produces an audit
event, and must never remove the user's only available sign-in method.
- On small screens, the split frame becomes a single column and account controls
move before archival content.
- Public display names and private login usernames are distinct. Display names
support normalized Unicode and relaxed visible characters; login usernames
remain unique, ASCII-only credentials and must never appear on public-facing
community surfaces. Authorized ISAC user operations may show both.
### Third-party identity buttons
- Follow the identity provider's current official brand and sign-in guidelines.
- Use official, unmodified assets downloaded from the provider's brand resources.
- Discord sign-in uses the official white Discord symbol on Blurple `#5865F2`
with the explicit label “Continue with Discord.”
- Discord account connection controls use the same official symbol and Blurple
treatment with the explicit label “Link Discord.”
- Sign-in pages group external providers into a compact, equal-weight provider
rail. Keep a short visible provider name beneath each mark; accessible names
and hover text are supplementary and do not replace required brand wording.
- Google uses its standard multicolor G on a white icon field, Apple uses a
white Apple mark on black, Discord uses its unmodified white symbol on
Blurple, and Steam uses its white linked-circle mark on Steam navy.
- Providers that are not configured are disabled, desaturated, and marked
`PLANNED`; they must not navigate, submit, or visually imply availability.
- When each provider is implemented, replace its placeholder with the
provider-rendered control or current pre-approved sign-in artwork where the
provider requires it. In particular, use Google Identity Services or its
approved icon-mode asset and Steam's published sign-in image.
- Preserve the provider's required clearspace, logo proportions, approved color,
readable contrast, and text/logo alignment even when the surrounding surface
follows the SHD theme.
- Provider buttons still require SHD.build's focus-visible, pressed, pending, and
duplicate-interaction protection where those states do not conflict with the
provider's branding requirements.
- Authentication uses one unified access screen rather than separate sign-in and
registration destinations. Verified email and first-time OAuth identities may
create an account; returning identities sign into the matching account.
- Password access uses an explicit `SIGN IN` / `CREATE ACCOUNT` mode switch
inside the fallback panel. Account creation separates the public display name
from the private ASCII login username.
- Passkeys are a returning-user method on this screen. New agents first establish
an account through verified email, OAuth, or local credentials, then enroll a
passkey from Account Access.
### Footer and legal surfaces
- Every routed page ends with the global SHD footer containing Terms & Privacy,
data-retention access, and the unofficial Ubisoft fan-site disclaimer.
- Legal pages retain the command-console visual language but prioritize readable
serif body copy, anchored sections, and restrained line length.
- Login security metadata is operationally visible in ISAC for 30 days. After
that period, IP, user-agent, normalized client/device fields, and credential
references and proxy-supplied approximate location are scrubbed while
non-sensitive event facts, categorical risk flags, and session outcomes may remain.
### Admin dashboard
- Use `admin-page`, `admin-command`, `admin-dashboard`, `admin-sidebar`, and `admin-content`.
- The administrative system is named ISAC. Separate navigation into explicit
operational domains such as User Operations and Data Management; visibility
must reflect server-provided capabilities.
- User Operations shows every supported authentication method as operational
metadata: local credentials, verified email, passkeys, Discord, and planned
providers. Identity-removal controls require `users.identities`, create audit
records, and preserve at least one remaining sign-in method.
- The Agent Registry prioritizes assigned roles over authentication-method
summaries. Authentication details belong in the individual agent dossier.
- ISAC authentication-method removal is always a two-step interaction contained
within the affected method row. The confirmation state explains the impact and
provides explicit Cancel and orange Confirm actions before submission.
- Agent dossiers consolidate operational controls into full-width tabs for
Roles & Permissions, Authentication, and Moderation. Keep dense controls in
their relevant tab instead of allowing one dashboard column to grow far beyond
adjacent content.
- Avatar removal uses the same in-card, two-step confirmation interaction as
authentication-method removal.
- Role and permission changes require a modal review step that summarizes the
complete selected role and direct-permission sets. Only the modal's orange
Confirm action submits the assignment.
- Access-review summaries are diffs: retained assignments use a neutral `KEEP`
state, additions use green `ADD`, and removals use red `REMOVE` with struck
assignment text. Added and removed items appear together in their respective
role or direct-permission column.
- Login, build/guide, and comment histories are independent support registries.
Each provides context-appropriate filters and namespaced pagination controls
so changing one history page does not reset the others.
- Each module starts with `module-toolbar`, followed by `module-kpis`.
- Editors use `dashboard-editor` and appear before the affected table.
- Data collections use `dashboard-table`, `dashboard-row`, and `table-heading`.
- Keep tables dense and horizontally scrollable rather than wrapping columns unpredictably.
- User dossiers pair access controls and moderation in a two-column console,
followed by compact login and content-history streams. Restriction state must
be textual and use the danger color; inactivity remains a separate activity
classification rather than a punishment state.
- Role names describe durable organizational responsibility. `Admin` is the
unrestricted administrative role; `Community Oversight` is reserved for
community content moderation and does not imply ISAC access. Operational
ISAC access is delegated separately through scoped roles and permissions.
- Roles & Permissions is a separate User Operations registry. Role definitions
compose discrete capabilities through a dense permission catalogue with an
explicit selected count and textual `GRANTED` / `NOT GRANTED` states. The
built-in Admin role is visible but system-protected. Delegated access managers
must never be able to grant `system.admin`; both option visibility and
server-side validation enforce this boundary. Role mutations are recorded in
the audit log with their previous and resulting permission sets.
- Audit History belongs to a separate `SYSTEM OVERSIGHT` navigation domain.
Audit records are append-only operational evidence and show the operator,
categorical action, target identifier, timestamp, and expandable before/after
JSON snapshots. Search and category/action filters run before pagination.
The Auditor role grants read-only `audit.view` access plus entry to ISAC;
audit visibility never implies mutation, user-management, or game-data access.
- Supported audit events may expose a permissioned compensating-action control.
Reversion uses a danger-styled `ATTEMPT REVERT` entry action followed by a
modal that explains the original action, operator, target, and conflict
checks. The orange Confirm action is the only submission path. ISAC compares
current state with the original event’s after-snapshot before restoring the
before-snapshot; newer work blocks the operation. Successful reversions append
a new `audit.reverted` event and never alter the original history. `audit.view`
remains read-only; `audit.revert` is independently assigned.
- System Metrics is the second read-only System Oversight surface. It uses a
compact KPI row for headline process health and a two-column grid of dense
runtime, host, database, and service-volume panels. Refresh is explicit and
duplicate-safe; optional auto-refresh is visibly selected and uses a
restrained ten-second interval. Metrics must not expose environment values,
credentials, full filesystem paths, or other deployment secrets. The
`metrics.view` permission is independent of mutation access and is included
in the read-only Auditor role.
- Account deletion uses a collapsed danger zone, explicit identity confirmation,
and plain-language retention guidance. Soft-deleted accounts retain authored
content under a deleted-agent identity while releasing credentials, usernames,
external identity links, sessions, roles, and permissions.
- Threshold-based set bonuses use compact `effect-band` groups. Each threshold is
displayed as a fixed piece-count marker followed by its mapped stat and value,
keeping progression readable in editors and table summaries.
- Multi-value compatibility fields use a dense `selection-grid` of checkbox
rows with a visible selected-count summary. Keep the entire row clickable and
preserve native checkbox semantics for keyboard and assistive-technology use.
- When compatibility is conditional on another field, show only valid choices,
clear stale selections when the controlling field changes, and state required
minimum selections in both the section label and validation feedback.
- Tiered records with shared structure use one shared selector and side-by-side
value columns rather than duplicating the entire editor. Template-driven copy
must show live previews for every tier and document its placeholder syntax.
### Forms
- Labels are uppercase and letter-spaced.
- Inputs use dark surfaces, one-pixel borders, and clear disabled styling.
- Related min/max fields remain visually paired.
- Small mutually exclusive option sets use a compact segmented radio control,
even when visually presented like selectable checkbox cells. Include an
explicit “None” option when the field is optional.
- Primary save actions sit at the lower right. Cancel is secondary.
- Destructive/archive actions are visually separated from save actions.
## Interaction rules
- Every interactive element needs a pointer cursor unless disabled.
- Buttons have hover, pressed, focus-visible, pending, and disabled states.
- Forms that send requests should use `PendingForm.svelte` or equivalent enhancement to prevent duplicate submissions.
- Pending buttons use `aria-busy="true"` and remain disabled until the request completes.
- Respect `prefers-reduced-motion`.
## Color semantics
- Orange: primary action, current location, selected operational value.
- Green: online, active, configured, or successful.
- Red: destructive action, error, or offensive classification when context requires it.
- Blue: defensive or informational classification.
- Gray: inactive, archived, unavailable, or supporting metadata.
Do not communicate state by color alone; include a label, icon, or pattern.
## Responsive behavior
- Collapse the dashboard sidebar into a two-column module grid below 900px.
- KPI tiles become two columns on small screens.
- Tier editors stack vertically on tablets.
- Tables retain a useful minimum width and scroll horizontally.
- Primary and secondary toolbar actions may expand equally on narrow screens.
## Adding a new admin module
1. Add the route beneath `src/routes/admin`.
2. Register it in the admin layout navigation.
3. Start with the module toolbar and KPI row.
4. Reuse dashboard editor and table classes.
5. Use the shared tokens instead of introducing near-duplicate colors.
6. Verify keyboard focus, pending behavior, empty states, mobile layout, and archived data behavior.
If a new interface needs a genuinely new pattern, document it here when introducing it.
## Design-system governance
Significant visual and interaction changes must update this document and the
shared implementation in the same change. A change is significant when it
introduces or materially revises a reusable token, component pattern, layout,
responsive rule, accessibility behavior, motion behavior, or state convention.
Small alignment corrections and isolated visual bug fixes do not require a
documentation change unless they establish a rule that other interfaces should
follow.
Repository agents and contributors should follow the maintenance checklist in
`AGENTS.md`.
### Agent avatars
Agent portraits use a circular crop in identity headers and square tactical
thumbnails in selectors. Preset choices appear in a compact four-column grid;
the active choice uses the orange action border and an explicit pressed state.
Custom images are normalized server-side to a metadata-free 256 × 256 WebP.
Selectors must retain visible hover, focus-visible, pressed, pending, and
disabled states, and collapse naturally with their containing account console.
ISAC user dossiers show the current portrait, distinguish preset and custom
sources textually, and place destructive custom-image removal behind the
existing moderation permission and pending-action pattern.
Moderation actions use full-width engineered controls: neutral outlined
buttons for reversible identity changes and muted red controls for destructive
or restrictive changes. Every control must expose pointer, hover,
focus-visible, pressed, disabled, and inline pending-spinner states; adjacent
navigation links use the same height, typography, and interaction motion.
### Weapon definition editor
Complex progression definitions use a stacked control-surface editor: identity
and fixed values first, then parallel tier cards, mutually exclusive talent
pools, fixed base bonuses, and the augmentation sequence. Tier cards retain
identical row ordering so values can be compared horizontally on wide screens
and stack without changing meaning on narrow screens. System-derived augment
steps appear as read-only numbered cells; editable effects use the shared
attribute/value row pattern. Exotic is a status layered onto a weapon family,
never a replacement for the family classification. Fixed base bonuses remain
visually separate from tactical augmentation effects. Exotic definitions add a
dedicated exotic-only talent after the two standard talent pools; their sixth
augmentation cell communicates that this talent advances to Tier II.
The exotic talent is owned by exactly one exotic weapon and is authored inline
inside that weapon editor, never selected from a shared global pool. Its
engineered sub-panel includes the talent name, shared description template,
Tier I/II previews, reusable triggers, and paired effect values. The Talent
Registry may display an owned exotic talent for discovery, but routes editing
back to its weapon rather than opening the shared-talent editor.
Large relationship sets use the searchable assignment control instead of
checkbox walls. It keeps assigned records visible as removable chips, filters
available records by name, renders at most thirty results at once, and exposes
counts for both assignments and matches. Mutually exclusive pools pass their
assigned IDs to one another as exclusions so invalid combinations cannot be
selected. Keyboard focus, pressed state, empty results, and overflow remain
explicit.
Where a relationship has a global slot invariant, filter each assignment
control at the data boundary instead of presenting cross-slot choices. Weapon
talents are classified once as Talent 1 / Top or Talent 2 / Bottom in the
talent registry; weapon editors only curate subsets from the matching slot.
### Game-semantic iconography
Canonical game icons are registered in `src/lib/game-icons.ts` and rendered
through `GameIcon.svelte`; do not repeat asset paths in individual features.
Use damage icons beside Blast, Pierce, and Shredding classifications, and core
attribute icons beside Firepower, Toughness, and Engineering values. The same
registry reserves the Bulwark, Combat Medic, Demolitionist, Tech Operator,
Vanguard, Legendary, and SHD-ticket assets for controls or data that explicitly
represent those concepts. Do not use semantic icons as unrelated decoration.
Interactive icon choices retain a visible text label, square engineered cells,
orange selected state, and hover, pressed, and focus-visible feedback. Icons
that repeat an adjacent visible label are decorative with an empty alternative;
standalone icons expose the registry's human-readable label. Preserve each
asset's aspect ratio with `object-fit: contain` and scale through the shared
`.game-icon` class rather than modifying source artwork.
### Item quality
Item quality is a global semantic scale: Standard uses
`--quality-standard` green, Specialized uses `--quality-specialized` blue,
Superior uses `--quality-superior` purple, and High-end uses
`--quality-high-end` yellow. Apply the matching `.quality-*` utility wherever
an item’s persisted quality is shown. Registry labels use `.quality-chip` so
quality remains explicit in text and never depends on color alone. These colors
identify item quality; orange remains reserved for actions and current
selection.
### OS Protocol editor
OS Protocol definitions separate shared secondary profiles from item-owned
progression. The twelve quality + attribute-type combinations are configured
once in a compact matrix and inherited by every matching protocol. Each profile
contains three fixed stat identities and editable values. Individual protocol
editors show the inherited profile read-only and store one unique primary stat
with a level-1 base value. That primary value scales linearly to exactly twice
its base at level 50.
Protocol identity forms stack the four-choice quality radio band above the
three-choice secondary-profile type band, with the protocol name occupying the
larger adjacent column. Quality choices use their global semantic color plus an
explicit text label and selected underline; profile types retain their
icon-backed labels. Both controls collapse below the name on narrow screens.
The shared secondary-profile matrix is collapsed by default because it is
configuration infrastructure rather than a frequent protocol-editing task. Its
disclosure header always exposes the configured total, uses a textual title,
and rotates the plus indicator when expanded. The full matrix remains keyboard
operable and follows the shared hover, focus-visible, and pressed states.
### Game-data icons
OS Protocols, brand sets, and talents use the shared game-data icon upload
control in their ISAC editors. Existing artwork is previewed and may be
replaced or explicitly removed. Registry identity cells render a compact
thumbnail before the record name and retain a neutral textual fallback when no
icon is configured.
Source artwork must be a transparent SVG, PNG, WebP, or AVIF no larger than
2 MiB. SVG is treated only as an upload source and never served directly.
Accepted images are normalized asynchronously to a metadata-free transparent
256 × 256 WebP with `contain`, preserving the full symbol without avatar-style
cropping. Image labels remain visible in the UI, so icons supplement rather
than replace textual identity. Upload, replace, remove, pending, validation,
focus-visible, and narrow-screen states follow the shared engineered form
language.
For compact editors such as brand sets, place the icon rail beside the record
name and its primary configuration rows instead of giving the upload control a
full-width band. Keep destructive archive controls isolated on the left side of
the action bar and use the established `.moderation-action.danger` treatment;
save and cancel remain grouped on the right.
Archived records that support restoration replace their destructive archive
control with a green outlined `.moderation-action.restore` control in the same
left-side position. The label must explicitly say “Unarchive” or “Restore”;
never communicate restoration by color or icon alone.
The dedicated unique-talent panel uses five interactive diamonds: no filled
diamonds is the base definition, and each selected upgrade adds one fifth of
the base until five upgrades show exactly twice the base effect.
Diamonds are both a progression preview and an explicit numeric state; expose
their upgrade number and `aria-pressed` state rather than relying on fill color.
Protocol talents own their effects but reuse the global stat and trigger
registries. Shared secondary values do not scale with the individual protocol’s
level. Store only the unique primary and talent base values, and derive their
progression consistently in calculation and display code.
### ISAC editor lifecycle
Successful saves have a consistent outcome throughout data management:
editing an existing record closes the editor and returns the user to the registry;
creating a new record keeps the editor open with a fresh blank definition for
rapid consecutive entry. Failed validation leaves the current editor and
entered values intact. Use a unique action result token so reactive handling
runs exactly once and does not create update loops.
Tiered-definition registries should show their rendered tier effects when the
text is operationally useful. Use compact wrapping description cells rather
than replacing meaningful data with a generic “configured” label; retain an
explicit textual missing state when a tier has no rendered description.
### Registry pagination
Every primary ISAC registry uses server-side pagination. The shared control
appears immediately above and visually attached to its table. It shows the
visible record range and total, previous/next navigation, a compact
window of page numbers, and row-count presets of 10, 25, 50, and 100. Existing
filter query parameters must survive page navigation, while changing page size
returns to page one. Summary metrics remain global or filter-global and must
never silently describe only the visible page. On narrow screens, retain
previous, next, current page, and page-size controls before optional page
numbers.
### Registry metric filters
The KPI row above an ISAC registry is an operational filter surface, not passive
decoration. Use `KpiFilters.svelte` when each metric describes a meaningful
record subset. The first card returns to the complete current registry or search;
the remaining cards filter by useful classifications such as active state,
category, equipment behavior, or restriction state.
Filtering is server-backed and occurs before pagination. Filter links preserve
compatible search and page-size parameters, reset the page number, remain
bookmarkable, and expose the selected state with both orange emphasis and
`aria-current`. Cards require pointer, hover, focus-visible, pressed, and
textually identifiable active states. Counts describe the full search scope,
not merely the visible page. Do not use aggregate facts that cannot filter the
affected registry—replace them with actionable subsets.
### Image uploads
All image uploads use the shared SHD drop-zone treatment and expose three equivalent
selection paths: a file picker, drag and drop, and clipboard paste. The control shows
the selected filename and a local preview, but server-side format, size, transparency,
and normalization checks remain authoritative.
### Moderated data states
ISAC must clearly distinguish direct editing, contributor proposals, and read-only
access. Use a compact access banner above the module rather than changing the
registry layout. Pending proposal counts appear as orange numeric indicators in
data-navigation items. Proposal lifecycle states use text as well as color:
pending is orange/actionable, approved is green/configured, and rejected or
failed is red/archived. Review decisions always use the standard ISAC confirmation
surface and must never apply a proposal from a table-row click alone.
Eligible contributors enter ISAC data modules in read-only mode by default.
The access banner pairs the explicit `READ-ONLY DATA ACCESS` state with a compact
action that opens the versioned contributor guidelines. Contributor mode may
only be enabled after affirmative checkbox acceptance. Once enabled, the banner
changes to orange, explains that saves enter moderation, and offers a
`RETURN TO READ-ONLY` toggle. Disabling is immediate and reversible and does not
withdraw existing proposals. Use text for every mode state; color alone is
insufficient. At narrow widths, stack the explanation and full-width toggle.
Read-only mode is an inspection surface: hide add controls, row edit actions,
mutation forms, and editors opened through URL state. Do not merely dim or
disable them. Registry navigation, KPI filters, pagination, search, evidence,
and other non-mutating inspection controls remain visible and interactive.
The ISAC command-status cluster includes an explicit `DATA MODE` cell alongside
system, access, and environment. It reports the highest effective data authority
in this order: `ADMIN`, `OVERSIGHT`, `DATA MANAGER`, `CONTRIBUTOR`, then
`READ-ONLY`. Use a neutral treatment for read-only, orange for contributor,
blue for Oversight authority, and green for direct-management authority. The
label and value are mandatory because color is supplemental. At medium widths
the four cells become a two-column grid; on narrow screens the cluster spans
the command header width.
### Oversight proposal corrections
User-facing references to moderators and data approvers use the SHD term
`Oversight`. Distinguish `Community Oversight` from `Data Oversight` when a role
name must identify its operational domain.
Pending proposal review uses three equal decision controls: approve, correct,
and reject. `CORRECT` is limited to small text or numeric fixes. Present the
stored form fields in a compact two-column correction grid and identify their
original field names; long descriptions and structured JSON values use
textareas. Uploaded file evidence is visible but immutable. Every correction
must be separately saved and audit logged before approval, and material changes
should be rejected for contributor revision. Collapse the decision controls and
correction fields to one column on narrow screens.
Data-navigation links with pending proposals use a dedicated four-column layout:
module code, flexible label, square orange count cell, then navigation arrow.
Never insert a count into the ordinary three-column link without changing its
grid, because the arrow will wrap to another row. The count includes textual
assistive labeling and strengthens its border and contrast on link hover or
active state.
Pending records may be used as dependencies in later proposals by any
contributor. Render these choices in the ordinary assignment control with a
restrained orange border/background and the explicit text `PENDING` plus the
proposer's display name; never present them as live data. Approval is dependency
ordered: a dependent proposal stays pending until every referenced proposal is
approved, while rejected or failed dependencies block it. This state must be
conveyed by text as well as color and must remain legible in compact and
responsive editor layouts.
Audit History may use a five-column KPI filter rail when all durable operational
domains need first-class visibility. It retains the standard compact KPI height
and collapses through the shared dashboard breakpoints; do not increase card
height or create a second row solely to accommodate the fifth domain.
Inherent permissions that cannot be removed through role or user assignment use
the compact blue information rail above the affected access controls. Always
name the baseline and enumerate its capabilities so operators do not mistake an
empty role assignment for an account with no effective access.
### Mobile registry detail targets
On narrow screens, a non-editing registry row with one canonical detail or
review destination becomes a full-row tap target. Use a real stretched link
when the destination is another route and a transparent button when it opens an
in-page detail surface. Keep the explicit desktop `VIEW`, `REVIEW`, or
`EVIDENCE` action, and add a visible mobile cue at the bottom of the row so the
interaction is discoverable.
The target must expose an accurate accessible name, show the standard orange
focus-visible outline, provide pressed feedback, and meet a minimum 48-pixel
tap height. Do not apply this pattern to edit, delete, approve, or other
mutating actions, and do not stretch a target across rows containing independent
interactive controls.