ms-ai-architect/playground/vendor/playground-design-system
Kjell Tore Guttormsen f1f27a4343 feat(ms-ai-architect): re-sync vendored design-system, source_commit now true [skip-docs]
DS-repo restored scripts/sync-design-system.mjs with an explicit source
allowlist and verified the command; ran their exact command (never one
reconstructed locally). MANIFEST.json was rewritten by the script itself,
never edited by hand.

source_commit now reads efaa3d0 (playground-design-system's main on the
public mirror), verified reachable via git ls-remote against the public
remote and git cat-file -t locally — in contrast to the previous c1b7bad,
which does not exist as a git object in that repo at all. 26/27 files
byte-identical to the source; only their README.md content differs.

Replaced the three stale prose points in README.md and docs/playground.md
that described the missing command and the untrustworthy source_commit.

Suite: 1070/1070 (tracked kb-update + kb-eval test files).

[skip-docs]: README.md and docs/playground.md are the doc update this task
required (vendoring section accuracy). CLAUDE.md's command/agent/skill
surface is unaffected — no new commands, agents, or skills.
2026-08-27 10:40:57 +02:00
..
fonts feat(ms-ai-architect): vendor playground-design-system v0.1 [skip-docs] 2026-05-03 12:25:42 +02:00
schemas feat(ms-ai-architect): vendor playground-design-system v0.1 [skip-docs] 2026-05-03 12:25:42 +02:00
base.css feat(ms-ai-architect): v1.15.0 — playground v3 project-view integration 2026-05-16 20:58:51 +02:00
CHANGELOG.md feat(ms-ai-architect): v1.15.0 — playground v3 project-view integration 2026-05-16 20:58:51 +02:00
components-tier2.css feat(ms-ai-architect): vendor playground-design-system v0.1 [skip-docs] 2026-05-03 12:25:42 +02:00
components-tier3-supplement.css feat(playground-design-system): v0.4.0 — root-cause fix for kanban/expansion/matrix-bubble [skip-docs] 2026-05-08 20:03:20 +02:00
components-tier3.css feat(ms-ai-architect): vendor playground-design-system v0.1 [skip-docs] 2026-05-03 12:25:42 +02:00
components-tier4-project-view.css feat(ms-ai-architect): v1.15.0 — playground v3 project-view integration 2026-05-16 20:58:51 +02:00
components.css feat(playground-design-system): v0.4.0 — root-cause fix for kanban/expansion/matrix-bubble [skip-docs] 2026-05-08 20:03:20 +02:00
fonts.css feat(ms-ai-architect): vendor playground-design-system v0.1 [skip-docs] 2026-05-03 12:25:42 +02:00
MANIFEST.json feat(ms-ai-architect): re-sync vendored design-system, source_commit now true [skip-docs] 2026-08-27 10:40:57 +02:00
print.css feat(ms-ai-architect): vendor playground-design-system v0.1 [skip-docs] 2026-05-03 12:25:42 +02:00
README.md feat(ms-ai-architect): re-sync vendored design-system, source_commit now true [skip-docs] 2026-08-27 10:40:57 +02:00
tokens.css feat(ms-ai-architect): v1.15.0 — playground v3 project-view integration 2026-05-16 20:58:51 +02:00

playground-design-system

Vendored, framework-free CSS design system for plugin playgrounds — design tokens, four component tiers, self-hosted fonts, and file:// operation with no build step.

Playgrounds are the visual self-service UIs that complement a plugin's terminal slash-commands. This system gives them one shared visual language: Aksel/Digdir-aligned aesthetics for Norwegian public-sector users, WCAG 2.1 AA contrast and focus handling, and pages that open straight from disk with no server.

Version: 0.6.0 — see CHANGELOG.md.

Table of Contents

Non-goals

  • Not a JavaScript component library. The system is CSS-only. Interactivity (tab state, sidepanel toggling, live-meter updates) is wired by each Playground in vanilla JS.
  • Not a general-purpose web UI kit. Scope is the Playgrounds in this marketplace; Aksel/Digdir conventions and domain visuals (NS 5814 matrices, EU AI Act tiers) are baked in rather than configurable.
  • No build step, bundler or npm package. Files are vendored and linked with plain <link> tags. Nothing is compiled, and nothing is published to a package registry.
  • No icon set. Iconography is left to each Playground so the shared system stays small.
  • Not open to pull requests. Solo project — see Contributing.

Provenance

This design system was generated by claude.ai/design (Anthropic) in a dialog-based design session driven by a comprehensive brief covering five plugins (ms-ai-architect, okr, llm-security, ultraplan-local, config-audit), Norwegian public-sector design conventions (Aksel/Digdir), and domain-specific visual standards (NS 5814 risk matrices, EU AI Act 4-tier pyramide, Doerr OKR scoring, NIST CSF, OWASP threat modeling).

Integration into the marketplace (file organization, path normalization, README authoring, root-doc cross-references) was performed in a separate Claude Code session. Per Anthropic Consumer Terms §4, ownership of outputs is assigned to the user; this design system is licensed MIT alongside the rest of the marketplace.

Directory layout

playground-design-system/              # This repo
├── README.md                          # This file
├── tokens.css                         # CSS custom properties (Aksel/Digdir-aligned)
├── base.css                           # Reset, typography, primitives, focus, print
├── components.css                     # Tier 1: radar, matrix, findings-browser, critique-card, wizard, live-meter
├── components-tier2.css               # Tier 2: decision-tree, traffic-lights, diff-review, treemap, distribution, command-pipeline, pyramide, pipeline-cockpit, verdict-pill+risk-meter, codepoint-reveal, small-multiples, OWASP badges
├── components-tier3.css               # Tier 3 wave 1: pair-before-after, AI Act timeline, 3-track entry, FRIA rights-matrix, capability-matrix, parallel-agent-status, ErrorSummary, GuidePanel
├── components-tier3-supplement.css    # Tier 3 wave 2 (12): toxic-flow, fleet-overview, kanban Keep/Review/Remove, maturity-ladder, classify-and-transform, cycle-ribbon, persistent-antipattern, suppressed-signals, ExpansionCard, ReadMore, FormProgress, Aspirational-vs-Committed
├── components-tier4-project-view.css  # Tier 4: project-view arketype
├── fonts.css                          # @font-face declarations for self-hosted fonts
├── fonts/                             # Self-hosted woff2 + license attribution
│   ├── Inter-{Regular,Medium,SemiBold,Bold}.woff2
│   ├── JetBrainsMono-{Regular,Medium,SemiBold}.woff2
│   ├── SourceSerif4-{Regular,Semibold}.woff2
│   └── LICENSES.md                    # All three are SIL OFL 1.1
├── print.css                          # A4 print stylesheet with B/W severity patterns
├── schemas/                           # Cross-plugin JSON schemas
│   ├── finding.schema.json            # Used by llm-security, config-audit, ultraplan-review, ms-ai-review
│   ├── okr-set.schema.json            # Used by OKR plugin
│   └── ros-threat.schema.json         # Used by ms-ai-architect ROS workflow
├── scripts/
│   └── sync-design-system.mjs         # Vendors the delivered files into a consumer (see Vendoring and re-sync)
├── tests/
│   └── sync-source-boundary.test.mjs  # Pins what the sync may and may not copy
└── playground-examples/               # Showcase + reference scenarios (this repo's own demos)
    ├── index.html                     # System showcase (browse all components)
    ├── ros-lier-kommune.html          # Scenario A — ms-ai-architect ROS report
    ├── okr-baerum.html                # Scenario B — OKR live writer
    ├── security-direktorat.html       # Scenario C — llm-security findings review
    ├── templates.html                 # Skeleton + print-template demos
    ├── tier3-preview.html             # Tier 3 wave 1 visual preview
    ├── components/                    # Tier 3 wave 2 — 12 isolated demo pages
    │   ├── sankey-toxic-flow.html
    │   ├── fleet-overview.html
    │   ├── kanban.html
    │   ├── maturity-ladder.html
    │   ├── classify-transform.html
    │   ├── cycle-ribbon.html
    │   ├── persistent-antipattern.html
    │   ├── suppressed-signals.html
    │   ├── expansion-card.html
    │   ├── read-more.html
    │   ├── form-progress.html
    │   └── aspirational-committed.html
    ├── ros-app.js                     # Scenario A interactivity
    └── ros-data.js                    # Scenario A mock data

Consumers vendor this repo (its CSS/fonts/schemas, not playground-examples/) into their own Playground at <plugin>/playground/vendor/playground-design-system/ — copied in, not a git submodule or shared symlink. See Quick start.

Quick start

To use the design system from a plugin's Playground:

<!doctype html>
<html lang="nb" data-theme="light">
<head>
  <meta charset="utf-8">

  <!-- Theme bootstrap. Must run before the stylesheets parse to avoid a
       flash-of-wrong-theme (FOUC). Priority order:
         1) saved choice (localStorage '<plugin-name>-theme')
         2) OS preference via matchMedia('(prefers-color-scheme: dark)')
         3) the HTML attribute default ('light' above)
       Sets both data-theme + colorScheme for native form controls and scrollbars.
       Wrapped in try/catch — file:// + private mode can block localStorage. -->
  <script>
    (function () {
      var theme = null;
      try {
        var saved = localStorage.getItem('<plugin-name>-theme');
        if (saved === 'light' || saved === 'dark') theme = saved;
      } catch (e) { /* localStorage unavailable */ }
      if (!theme && window.matchMedia) {
        theme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
      }
      if (!theme) theme = document.documentElement.getAttribute('data-theme') || 'light';
      document.documentElement.setAttribute('data-theme', theme);
      document.documentElement.style.colorScheme = theme;
    })();
  </script>

  <link rel="stylesheet" href="vendor/playground-design-system/tokens.css">
  <link rel="stylesheet" href="vendor/playground-design-system/base.css">
  <link rel="stylesheet" href="vendor/playground-design-system/components.css">
  <link rel="stylesheet" href="vendor/playground-design-system/components-tier2.css">
  <!-- Optional: include components-tier3.css for Tier 3 wave 1 components -->
  <!-- Optional: include components-tier3-supplement.css for Tier 3 wave 2 (12 additional components) -->
  <!-- Optional: include components-tier4-project-view.css for the Tier 4 project-view arketype -->
  <!-- Optional: only include print.css if scenario produces a printable A4 report -->
  <link rel="stylesheet" href="vendor/playground-design-system/print.css">
  <!-- Self-hosted fonts (no external requests) -->
  <link rel="stylesheet" href="vendor/playground-design-system/fonts.css">
</head>
<body>
  <header class="app-header">
    <a class="app-header__brand" href="...">
      <span class="app-header__brand-mark">MS</span>
      ms-ai-architect
    </a>
    <span class="app-header__breadcrumb">/ Playground</span>
    <div class="app-header__spacer"></div>
    <button class="theme-toggle" data-theme-toggle>Mørk modus</button>
  </header>
  <!-- Your Playground content using design-system classes -->
</body>
</html>

The relative path vendor/playground-design-system/ assumes the plugin's Playground HTML lives at <plugin-name>/playground/<plugin-name>-playground.html, with the design system vendored (copied in) at <plugin-name>/playground/vendor/playground-design-system/. Adjust the prefix to match your plugin's structure.

The theme-bootstrap script is not part of the vendored CSS — copy it into each Playground's own <head>, replacing <plugin-name>-theme with a key unique to that plugin (both ms-ai-architect and llm-security follow this pattern today). The data-theme-toggle button's own click handler (written per Playground, not vendored) is what writes that key via localStorage.setItem when the reader switches theme — the bootstrap script only reads it back on the next load. Without the bootstrap script, the page renders in the HTML attribute's default theme for one frame before JavaScript applies the saved/OS preference — the FOUC it exists to prevent.

Vendoring and re-sync

Vendoring remains the recommended consumer model. Measured 2026-08-27 across both consumers (ms-ai-architect, llm-security): 26 of 27 vendored files are byte-identical to this repo's current content three and a half months after their last sync, and neither copy has been edited locally. The only file that differs is this README.

Re-sync

From a checkout of this repo, with the consumer repo checked out alongside it:

node scripts/sync-design-system.mjs <consumer-name> --target ../<consumer-repo>

That rewrites <consumer-repo>/playground/vendor/playground-design-system/ — the 27 delivered files plus a regenerated MANIFEST.json. --target is the consumer's repo root; the script appends playground/vendor/playground-design-system/ itself. --source <dir> selects a different checkout of this repo to read from (default: the one the script lives in). Node 16.7+, no npm dependencies, no install step.

The script refuses to overwrite a vendored file that was edited locally since the last sync; --force overrides. It copies an explicit allowlist (DELIVERED_FILES in the script), not the repo root — STATE.md, .git/, docs/, playground-examples/, LICENSE and SECURITY.md stay here. tests/sync-source-boundary.test.mjs pins that boundary in both directions: nothing outside the allowlist reaches a consumer, and a new design-system file that is missing from the allowlist fails the sync loudly instead of silently not shipping.

node --test tests/sync-source-boundary.test.mjs

Checking a vendored copy

Integrity, from the consumer side, needs no source checkout:

node scripts/sync-design-system.mjs <consumer-name> --target ../<consumer-repo> --check

It re-hashes the vendored tree against that copy's own MANIFEST.json, then prints MANIFEST OK (27 files, source_commit ...) and exits 0, or lists the differing files and exits 2. It reads only — --check writes nothing to the consumer.

Without the script, do not compare a vendored copy to this repo with a plain diff or cmp. The sync injects /* Code generated by sync-design-system.mjs; DO NOT EDIT. */ as line 1 of every .css, and the source has no such line, so a raw comparison reports all nine stylesheets as drifted when none of them is. Measured 2026-08-27 against ms-ai-architect: raw cmp matches 17 of 27 files; strip line 1 from the vendored .css files and it is 26 of 27, the only real difference being this README. --check is immune, because it hashes the vendored tree against MANIFEST.json — which was built after the header was injected — and never against the source.

MANIFEST.json's source and source_commit fields in the existing copies still describe the old monorepo layout, and the recorded commit is not merely unreachable but inaccurate. Leave them alone: the next real re-sync rewrites both truthfully. Do not repair them by hand — rewriting only the path would turn an obviously stale pointer into a plausible false one. See docs/vendoring-and-re-sync.md for the full decision and the measurements behind it.

Design principles

  1. Aksel/Digdir-aligned. Inter font, body 17px, Digdir blue #0062BA, semantic CSS tokens. Norwegian public sector users recognize this DNA.
  2. WCAG 2.1 AA non-negotiable. Required by Forskrift om universell utforming av IKT for Norwegian public sector. Every component ships with proper focus rings, ARIA attributes, keyboard navigation, and contrast that passes deuteranopia simulators.
  3. Vanilla HTML/CSS/JS. No React, no Tailwind, no build step. A plugin can copy a Playground HTML file to disk and it will render correctly.
  4. Self-contained per Playground. Each plugin's playground/*.html should be openable offline with only the design-system CSS files alongside.
  5. Print-aware. The print.css stylesheet ensures matrix cells use B/W-safe hatching patterns when printed, severity badges become outlined boxes with patterns, and interactive chrome disappears. Designed for A4 reports going to Datatilsynet, kommunestyre, statsråd.
  6. Severity is universal. All severity-coded UI uses the same five-level ramp (low/medium/high/critical/extreme) with deuteranopia-safe hex values defined in tokens.css. Distinct from "state" tokens (failed/blocked/queued/running) used in pipeline contexts — never mix severity-red with failure-red.
  7. Two-spor strategy. The system supports both non-technical decision makers (Spor 1: ms-ai-architect, OKR, llm-security) and developer power-users (Spor 2: ultraplan-local, config-audit) — same component library, different information densities.

Token system

See tokens.css for full reference. Highlights:

  • Typography: --font-family-sans (Inter), --font-size-md (17px body), --measure (65ch line length)
  • Primary: --color-primary-500 = #0062BA (Digdir blue), with 50/100/300/500/700/900 ramp
  • Severity: --color-severity-{low,medium,high,critical,extreme} + -soft (background) + -on (foreground) variants. Deuteranopia-safe.
  • State: --color-state-{success,warning,failed,blocked,info,running,queued,pending,done} — distinct from severity
  • Surface: Warm off-white #FBFAF7 (light), graphite #0F1419 (dark). Theme via [data-theme="dark"] on <html> or <body>
  • Plugin scope: --color-scope-{architect,okr,security,ultraplan,config} for visual differentiation between plugins
  • Spacing: 4px grid, scale 1-20 (4px to 80px)
  • Radius: --radius-sm (3px) / -md (5px) / -lg (8px) / -pill (999px) — max 8px (no consumer-app rounded corners)
  • Motion: Respects prefers-reduced-motion

Component reference

Tier 1 (components.css)

Component Class prefix Used by
Radar / Spider chart .radar OKR maturity (7-axis), ms-ai security (6), ms-ai ROS dimensions (7), ultraplan plan-critic (7)
Matrix / 5×5 heatmap .matrix ms-ai ROS, DPIA, OKR coverage, security scanner, license map
Findings-browser .findings llm-security, ultraplan-review, config-audit, ms-ai-review
Critique-card .critique-card llm-security findings, ultraplan, config-audit feature-gap, OKR antipatterns
Wizard / Stepper .stepper, .wizard__panel ms-ai 5-step intake, security clean, config-audit audit, ultraplan, OKR onboarding
Live-meter .live-meter, .lint-annotation OKR writer, ultraplan brief-reviewer, cost, config-audit

Plus app-shell primitives: .app-header, .sidepanel, .scrim, .theme-toggle.

Tier 3 (components-tier3.css)

Critical components for ms-ai-architect Playground v3 plus universal Aksel patterns. Authored 2026-05-02 in Claude Code (not via claude.ai/design — visual coherence verified against Tier 1+2 in playground-examples/tier3-preview.html).

Component Class prefix Used by
Inherent + residual pair .pair-before-after ms-ai ROS before/after, DPIA, AI Act mitigations, OKR check-ins
AI Act compliance-tidslinje .aiact-timeline, .aiact-countdown ms-ai-architect classify flow + dashboard
3-track entry .tracks All plugins — entry-level UX choice (Guide/Explore/Expert)
FRIA rights-matrix .rights-matrix ms-ai-architect FRIA (Art. 27, 12 EU Charter rights × impact)
Capability-matrix .capability-matrix ms-ai-architect license × kapabilitet mapping
Parallel-agent-status .agent-grid, .agent-card ms-ai utredning multi-worker, ultraplan multi-wave execute
ErrorSummary .error-summary All plugins — Aksel/GOV.UK form-validation pattern
GuidePanel .guide-panel All plugins — Aksel friendly inline guidance with optional CTA

Tier 2 (components-tier2.css)

Component Class prefix Used by
Decision-tree .decision-tree, .dt-node, .dt-edge ms-ai AI Act 4-step classifier, security MAESTRO drill
Traffic-lights .traffic-light ms-ai compliance, OKR KR-status, security pre-deploy, config-audit risk
Diff-review .diff security diff, config-audit drift, ultraplan triage
Treemap .treemap config-audit token-hotspots
Distribution / range-viz .distribution ms-ai cost P10/P50/P90, security risk-score, OKR progress
Command-pipeline .cmd-pipeline, .cmd-step All plugins — final export of slash-command sequence
Pyramide (4-tier) .pyramide ms-ai AI Act risk classification
Pipeline-cockpit .pipeline-cockpit, .pc-stage ultraplan 6-stage flow, ms-ai utredning, config-audit audit
Verdict-pill + risk-meter .verdict-pill-lg, .risk-meter llm-security BLOCK/WARNING/ALLOW + 0-100 risk-score
Codepoint-reveal .codepoint-reveal llm-security Unicode steganography demo
Small-multiples grid .small-multiples, .sm-card llm-security 16-category posture (alternative to overcrowded radar)
OWASP badges .badge--owasp-{llm,asi,ast,mcp} llm-security finding cross-mapping (4 frameworks)

Schemas

schemas/ contains JSON schemas for cross-plugin data interchange:

  • finding.schema.json — universal "finding" shape (id, title, severity, source, evidence, rationale, recommendation, status). Consumed by llm-security, config-audit, ultraplan-review, ms-ai-review. Maps directly to the .critique-card component.
  • okr-set.schema.json — OKR shape (objectives + key results, scoring, antipattern annotations). Consumed by OKR plugin.
  • ros-threat.schema.json — ROS threat shape (likelihood × consequence, mitigation references, residual risk). Consumed by ms-ai-architect.

A plugin command can output JSON conforming to these schemas, and a Playground can render the result without further translation.

Theming

Default is light. Toggle dark via data-theme="dark" attribute on <html> or <body>. The system also respects prefers-color-scheme: dark when no explicit theme is set:

// Toggle dark/light
document.documentElement.dataset.theme =
  document.documentElement.dataset.theme === 'dark' ? 'light' : 'dark';
localStorage.setItem('theme', document.documentElement.dataset.theme);

Print mode

Include print.css if your scenario produces an A4 report. Then add class="no-print" to interactive chrome (header, buttons, theme toggle), and use class="page-break" to force page breaks. Severity-coded matrix cells will automatically render as B/W-safe hatching patterns when printed. The .print-header and .print-footer blocks support kommune-logo slots and signature lines for offentlige dokumenter.

Known limitations

  1. No JavaScript framework. Components are CSS-first. Interactivity (e.g. aria-selected toggling, sidepanel open/close, live-meter updates) must be wired by each Playground using vanilla JS. See playground-examples/ros-app.js for a reference implementation pattern.
  2. No icon set bundled. The system assumes Lucide or Phosphor SVG sprites are inlined per Playground. Iconography is intentionally out-of-system to keep the shared system small.
  3. Mobile responsiveness is partial. The 5×5 matrix, findings-browser, codepoint-reveal split-pane, and small-multiples grid have explicit @media (max-width: ...) rules. Other components may need polish for narrow viewports.

Self-hosted fonts

All three font families (Inter, JetBrains Mono, Source Serif 4) are bundled as woff2 in fonts/ and loaded via fonts.css. No external requests to Google Fonts or any CDN. All three are SIL OFL 1.1 — see fonts/LICENSES.md for full attribution.

Versioning

This system follows semver:

  • Major: Breaking token rename, component class rename, schema field removal/rename
  • Minor: New tokens, new components, new schema fields, new variants
  • Patch: Bugfixes, accessibility improvements, visual polish without contract changes

Every plugin Playground that consumes the design system should declare the version in a comment at the top of its HTML:

<!-- playground-design-system v0.1 -->

License

MIT, same as the parent ktg-plugin-marketplace. Reuse freely; attribution appreciated.

Contributing

This is a solo project. PRs are not accepted, but issues and suggestions are welcome at the marketplace repo (Forgejo: git.fromaitochitta.com/open/ktg-plugin-marketplace).

When adding a new component:

  1. Add CSS to components.css (Tier 1) or components-tier2.css (Tier 2)
  2. Use BEM naming convention: .component-name__element--modifier
  3. Reference only tokens.css custom properties — never hard-code colors, spacing, or fonts
  4. Test in light + dark themes, with deuteranopia simulator (Stark, Sim Daltonism)
  5. Test keyboard navigation and screen reader (NVDA on Windows, VoiceOver on Mac)
  6. Add a print rule if the component appears in printable reports
  7. Document in this README under the appropriate Tier table