diff --git a/plugins/ms-ai-architect/playground/vendor/playground-design-system/MANIFEST.json b/plugins/ms-ai-architect/playground/vendor/playground-design-system/MANIFEST.json new file mode 100644 index 0000000..a2fb5b8 --- /dev/null +++ b/plugins/ms-ai-architect/playground/vendor/playground-design-system/MANIFEST.json @@ -0,0 +1,35 @@ +{ + "generated_by": "scripts/sync-design-system.mjs", + "do_not_edit": true, + "source": "shared/playground-design-system/", + "source_commit": "f1fecf39b8fc20e86f6ec3c737f0dfda8403712e", + "sync_date": "2026-05-03T10:24:01.408Z", + "file_count": 25, + "files": { + "README.md": "83de0e29b207c979b7b2a3327b7a4ec0c2e1b4d3705ee2677f26c28c3a3ee643", + "base.css": "604fe6839e2ed304bc0ba112a4e045f208b4b3f084f449a1abdb94ce0a1e5263", + "components-tier2.css": "c2cb7e9d76d6af28d50db654030413777feb2f2f2b93213e598de8b686b14523", + "components-tier3-supplement.css": "5b70503ce81a4aefc269e894ab0ae0921ab48370a00de19c737354274f520387", + "components-tier3.css": "c391ea387298ce864bc35078e7e044b2cdd4187e3130456347d91876599ff4b1", + "components.css": "f76b22ba9fd64c2e806b4467536174347105f3e5ccca8a6349a919287d864b86", + "fonts.css": "e3c3df581c6e4d66e25c555f125c745f6512a33038401089d2519a94ea63ee3d", + "fonts/Inter-Bold.woff2": "220976705fbec109f43c5cfdceca639e99ace7e51f3eb67292b105d3575eb39b", + "fonts/Inter-Medium.woff2": "8458f8afa67b5691c1fcbe51607a2dafb53a9839e48131c608a186b65415d96d", + "fonts/Inter-Regular.woff2": "b6f9db9e45be20f3c1312c97fbee7ec36b7d8280f8caa4d53c9ba0408cc9997a", + "fonts/Inter-SemiBold.woff2": "8e52a861dc26ff4608c50bd7ff89b65d0d6216a2afe7b47ce5d84544811ca400", + "fonts/JetBrainsMono-Medium.woff2": "086c48dfbea9ddaff1320f7e09399b8e2924e88ce67453721255db3bdbb5a353", + "fonts/JetBrainsMono-Regular.woff2": "a9cb1cd82332b23a47e3a1239d25d13c86d16c4220695e34b243effa999f45f2", + "fonts/JetBrainsMono-SemiBold.woff2": "918edad542a1da608fd2ba8daebaff9ac802309103fe760eed465b8b4e47faf1", + "fonts/LICENSE-Inter.txt": "262481e844521b326f5ecd053e59b98c8b2da78c8ee1bdbb6e8174305e54935a", + "fonts/LICENSE-JetBrainsMono.txt": "30f0c136e3c88e422d0791acd97238870f9054a9729bc34cf2ff0d4ed8cac4ad", + "fonts/LICENSE-SourceSerif4.md": "75784a295293a8992f5a8d99210566e0064a012e6dab6731305e3787f15896c7", + "fonts/LICENSES.md": "16ef4cb2f4d85233c27be390c3f52ee60d24f1a2a5f72886a0c5dbc8cfcf2c28", + "fonts/SourceSerif4-Regular.woff2": "d5f6830fbdb42425cb60b5cd61d91afa9a2f59b8e99057b1a1d4c2e43b1b06dc", + "fonts/SourceSerif4-Semibold.woff2": "dd00d4b1fea42ca7bd806175662ec51ec09494de986d85087861216cbcf17add", + "print.css": "cd62f08d1b13e0308b5083b6cb5135739eb834e85e88468bd349a642d92b7a6f", + "schemas/finding.schema.json": "0b24797373650582bac232d31a4dd9260593375a0d17259e18f1141a20de8d0c", + "schemas/okr-set.schema.json": "aa27347fb232a956ec9dcee1775115710e2715a665c8d729ac50b90c6884de26", + "schemas/ros-threat.schema.json": "e16497c1a6b79d6e78149d6cf1c28ac9df1e93234627a0c546814fb24d6c96d9", + "tokens.css": "7598d5eda83e189418125cd73b8646e1b0d15a1c195b6f180fafa7944b5ba328" + } +} diff --git a/plugins/ms-ai-architect/playground/vendor/playground-design-system/README.md b/plugins/ms-ai-architect/playground/vendor/playground-design-system/README.md new file mode 100644 index 0000000..b54de64 --- /dev/null +++ b/plugins/ms-ai-architect/playground/vendor/playground-design-system/README.md @@ -0,0 +1,234 @@ +# Playground Design System + +A shared design system for plugin Playgrounds — visual self-service UIs that complement terminal slash-commands. Built for Norwegian public sector with WCAG 2.1 AA compliance, Aksel/Digdir-aligned aesthetics, and self-contained HTML deployment. + +**Version:** 0.1 (Phase 1 — 2026-05-02) + +## Provenance + +This design system was generated by **[claude.ai/design](https://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 + +``` +shared/ +├── playground-design-system/ # The design system (this directory) +│ ├── 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 +│ ├── 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 +│ +└── playground-examples/ # Showcase + reference scenarios + ├── 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 +``` + +## Quick start + +To use the design system from a plugin's Playground: + +```html + + + + + + + + + + + + + + + + +
+ + MS + ms-ai-architect + + / Playground +
+ +
+ + + +``` + +The relative path `../../shared/playground-design-system/` assumes the plugin's Playground lives at `plugins/{plugin-name}/playground/index.html`. Adjust the prefix to match your plugin's structure. + +## 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 `` or `` +- **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 `` or ``. The system also respects `prefers-color-scheme: dark` when no explicit theme is set: + +```js +// 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: + +```html + +``` + +## 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 diff --git a/plugins/ms-ai-architect/playground/vendor/playground-design-system/base.css b/plugins/ms-ai-architect/playground/vendor/playground-design-system/base.css new file mode 100644 index 0000000..abeb790 --- /dev/null +++ b/plugins/ms-ai-architect/playground/vendor/playground-design-system/base.css @@ -0,0 +1,264 @@ +/* Code generated by sync-design-system.mjs; DO NOT EDIT. */ +/* ============================================================================= + base.css — reset, typography, layout primitives, focus, print + ============================================================================= */ + +*, *::before, *::after { box-sizing: border-box; } + +html { + -webkit-text-size-adjust: 100%; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + text-rendering: optimizeLegibility; +} + +body { + margin: 0; + font-family: var(--font-family-sans); + font-size: var(--font-size-md); + line-height: var(--line-height-normal); + color: var(--color-text-primary); + background: var(--color-bg); + font-feature-settings: "ss01", "cv11"; +} + +h1, h2, h3, h4, h5, h6 { + margin: 0; + font-weight: var(--font-weight-semibold); + line-height: var(--line-height-tight); + letter-spacing: -0.01em; + color: var(--color-text-primary); + text-wrap: balance; +} + +h1 { font-size: var(--font-size-3xl); letter-spacing: -0.02em; } +h2 { font-size: var(--font-size-2xl); letter-spacing: -0.015em; } +h3 { font-size: var(--font-size-xl); } +h4 { font-size: var(--font-size-lg); } +h5 { font-size: var(--font-size-md); } + +p { + margin: 0; + text-wrap: pretty; + max-width: var(--measure); +} + +small { font-size: var(--font-size-sm); color: var(--color-text-secondary); } +code, kbd, samp { font-family: var(--font-family-mono); font-size: 0.92em; } +kbd { + display: inline-block; + padding: 1px 6px; + font-size: 0.85em; + border: 1px solid var(--color-border-moderate); + border-bottom-width: 2px; + border-radius: var(--radius-sm); + background: var(--color-surface); + color: var(--color-text-secondary); + line-height: 1; +} + +a { + color: var(--color-text-link); + text-decoration: underline; + text-underline-offset: 2px; + text-decoration-thickness: 1px; +} +a:hover { color: var(--color-text-link-hover); text-decoration-thickness: 2px; } + +button { font-family: inherit; } + +/* Focus rings — WCAG */ +:focus-visible { + outline: 2px solid var(--color-border-focus); + outline-offset: 2px; + border-radius: var(--radius-sm); +} +:focus:not(:focus-visible) { outline: none; } + +/* ---------- Buttons ---------- */ +.btn { + display: inline-flex; + align-items: center; + gap: var(--space-2); + padding: 9px 16px; + font-size: var(--font-size-sm); + font-weight: var(--font-weight-medium); + line-height: 1.3; + border-radius: var(--radius-md); + border: 1px solid transparent; + cursor: pointer; + transition: background var(--duration-fast) var(--ease-default), + border-color var(--duration-fast) var(--ease-default), + color var(--duration-fast) var(--ease-default); + white-space: nowrap; + text-decoration: none; +} +.btn:disabled, .btn[aria-disabled="true"] { opacity: 0.5; cursor: not-allowed; } + +.btn--primary { background: var(--color-primary-500); color: var(--color-text-on-primary); } +.btn--primary:hover { background: var(--color-primary-700); } + +.btn--secondary { + background: var(--color-surface); + color: var(--color-text-primary); + border-color: var(--color-border-moderate); +} +.btn--secondary:hover { background: var(--color-bg-soft); border-color: var(--color-border-strong); } + +.btn--ghost { + background: transparent; + color: var(--color-text-primary); + border-color: transparent; +} +.btn--ghost:hover { background: var(--color-bg-soft); } + +.btn--destructive { background: var(--color-severity-critical); color: #fff; } +.btn--destructive:hover { background: var(--color-severity-extreme); } + +.btn--sm { padding: 5px 10px; font-size: var(--font-size-xs); } +.btn--lg { padding: 12px 20px; font-size: var(--font-size-md); } + +/* ---------- Badges / pills ---------- */ +.badge { + display: inline-flex; + align-items: center; + gap: 4px; + padding: 2px 8px; + font-size: var(--font-size-xs); + font-weight: var(--font-weight-medium); + line-height: 1.4; + border-radius: var(--radius-pill); + border: 1px solid var(--color-border-subtle); + background: var(--color-bg-soft); + color: var(--color-text-secondary); + white-space: nowrap; +} +.badge--severity-low { background: var(--color-severity-low-soft); color: var(--color-severity-low-on); border-color: transparent; } +.badge--severity-medium { background: var(--color-severity-medium-soft); color: var(--color-severity-medium-on); border-color: transparent; } +.badge--severity-high { background: var(--color-severity-high-soft); color: var(--color-severity-high-on); border-color: transparent; } +.badge--severity-critical { background: var(--color-severity-critical); color: var(--color-severity-critical-on); border-color: transparent; } +.badge--severity-extreme { background: var(--color-severity-extreme); color: var(--color-severity-extreme-on); border-color: transparent; } + +.badge--owasp { font-family: var(--font-family-mono); font-size: 11px; padding: 1px 6px; } + +.badge--scope-architect { background: var(--color-scope-architect); color: #fff; border-color: transparent; } +.badge--scope-okr { background: var(--color-scope-okr); color: #fff; border-color: transparent; } +.badge--scope-security { background: var(--color-scope-security); color: #fff; border-color: transparent; } +.badge--scope-ultraplan { background: var(--color-scope-ultraplan); color: #fff; border-color: transparent; } +.badge--scope-config { background: var(--color-scope-config); color: #fff; border-color: transparent; } + +/* ---------- Cards / surfaces ---------- */ +.card { + background: var(--color-surface); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-lg); + padding: var(--space-6); +} +.card--sunken { background: var(--color-surface-sunken); } +.card--raised { box-shadow: var(--shadow-sm); } + +/* ---------- Inline messages (Aksel 3-tier) ---------- */ +.inline-message { + display: flex; + gap: var(--space-3); + padding: var(--space-3) var(--space-4); + border-radius: var(--radius-md); + border-left: 4px solid; + background: var(--color-bg-soft); + font-size: var(--font-size-sm); + line-height: var(--line-height-snug); +} +.inline-message--info { border-color: var(--color-state-info); background: #EAF3FB; color: #08416B; } +.inline-message--success { border-color: var(--color-state-success); background: var(--color-severity-low-soft); color: var(--color-severity-low-on); } +.inline-message--warning { border-color: var(--color-state-warning); background: var(--color-severity-medium-soft); color: var(--color-severity-medium-on); } +.inline-message--error { border-color: var(--color-severity-critical); background: var(--color-surface); color: var(--color-text-primary); } +.inline-message--error strong, .inline-message--error b { color: var(--color-severity-critical); } + +[data-theme="dark"] .inline-message--info { background: #0E2A3F; color: #9CC0EA; } +[data-theme="dark"] .inline-message--error { background: var(--color-surface); color: var(--color-text-primary); } +[data-theme="dark"] .inline-message--error strong, [data-theme="dark"] .inline-message--error b { color: #F09095; } + +/* ---------- Form controls ---------- */ +.input, .select, .textarea { + width: 100%; + padding: 9px 12px; + font-family: inherit; + font-size: var(--font-size-sm); + line-height: 1.4; + color: var(--color-text-primary); + background: var(--color-surface); + border: 1px solid var(--color-border-moderate); + border-radius: var(--radius-md); + transition: border-color var(--duration-fast) var(--ease-default), + box-shadow var(--duration-fast) var(--ease-default); +} +.input:hover, .select:hover, .textarea:hover { border-color: var(--color-border-strong); } +.input:focus, .select:focus, .textarea:focus { + outline: none; + border-color: var(--color-primary-500); + box-shadow: var(--shadow-focus); +} +.textarea { min-height: 96px; resize: vertical; line-height: var(--line-height-normal); } + +.label { + display: block; + font-size: var(--font-size-sm); + font-weight: var(--font-weight-medium); + color: var(--color-text-primary); + margin-bottom: 6px; +} +.label__hint { display: block; font-size: var(--font-size-xs); color: var(--color-text-tertiary); font-weight: 400; margin-top: 2px; } + +/* ---------- Layout primitives ---------- */ +.stack { display: flex; flex-direction: column; gap: var(--space-4); } +.stack--lg { gap: var(--space-8); } +.stack--sm { gap: var(--space-2); } +.row { display: flex; gap: var(--space-4); align-items: center; } +.row--wrap { flex-wrap: wrap; } +.row--between { justify-content: space-between; } + +.container { max-width: var(--container-default); margin: 0 auto; padding: 0 var(--space-6); } +.container--wide { max-width: var(--container-wide); } +.container--narrow { max-width: var(--container-narrow); } + +.divider { + height: 1px; + background: var(--color-border-subtle); + border: none; + margin: 0; +} + +/* ---------- Utilities ---------- */ +.text-secondary { color: var(--color-text-secondary); } +.text-tertiary { color: var(--color-text-tertiary); } +.text-mono { font-family: var(--font-family-mono); } +.text-sm { font-size: var(--font-size-sm); } +.text-xs { font-size: var(--font-size-xs); } +.text-lg { font-size: var(--font-size-lg); } +.font-medium { font-weight: var(--font-weight-medium); } +.font-semibold { font-weight: var(--font-weight-semibold); } +.tabular { font-variant-numeric: tabular-nums; } + +.sr-only { + position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; + overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; +} + +/* ---------- Reduced motion ---------- */ +@media (prefers-reduced-motion: reduce) { + *, *::before, *::after { + animation-duration: 0.01ms !important; + transition-duration: 0.01ms !important; + } +} + +/* ---------- Print ---------- */ +@media print { + body { background: #fff; color: #000; font-size: 11pt; } + .no-print, button.btn, nav, .nav, .toolbar, .tweaks-panel { display: none !important; } + .card { border: 1px solid #000; box-shadow: none; break-inside: avoid; } + a { color: #000; text-decoration: underline; } + h1, h2, h3 { break-after: avoid; } + .matrix-cell { print-color-adjust: exact; -webkit-print-color-adjust: exact; } + @page { margin: 18mm; } +} diff --git a/plugins/ms-ai-architect/playground/vendor/playground-design-system/components-tier2.css b/plugins/ms-ai-architect/playground/vendor/playground-design-system/components-tier2.css new file mode 100644 index 0000000..6aa75e2 --- /dev/null +++ b/plugins/ms-ai-architect/playground/vendor/playground-design-system/components-tier2.css @@ -0,0 +1,352 @@ +/* Code generated by sync-design-system.mjs; DO NOT EDIT. */ +/* ============================================================================= + components-tier2.css — Tier 2 components (Phase 2) + 7. Decision-tree (AI Act 4-step) + 8. Traffic-lights + 9. Diff-review + 10. Treemap (config-audit token hotspots) + 11. Distribution / range-viz (P10/P50/P90) + 12. Command-pipeline output + 13. Pyramide (AI Act 4-tier) + 14. Pipeline-cockpit + 15. Verdict-pill with risk-meter + 16. Codepoint-reveal (security Unicode steg) + 17. Inherent + residual pair (already partially in Tier 1, formalize) + 18. Small-multiples grid + ============================================================================= */ + +/* DECISION-TREE — vertical flowchart with 4 colored terminals */ +.decision-tree { display: flex; flex-direction: column; align-items: center; gap: 0; } +.dt-node { + padding: 12px 18px; + background: var(--color-surface); + border: 1px solid var(--color-border-moderate); + border-radius: var(--radius-md); + font-size: var(--font-size-sm); + font-weight: var(--font-weight-medium); + text-align: center; + min-width: 240px; + max-width: 340px; +} +.dt-edge { + width: 1px; height: 28px; background: var(--color-border-moderate); + position: relative; +} +.dt-edge__label { + position: absolute; + left: 8px; top: 50%; transform: translateY(-50%); + font-size: 11px; color: var(--color-text-tertiary); + white-space: nowrap; + font-family: var(--font-family-mono); +} +.dt-node--terminal { color: #fff; border: none; padding: 14px 20px; font-weight: var(--font-weight-semibold); } +.dt-node--forbidden { background: var(--color-severity-extreme); } +.dt-node--high { background: var(--color-severity-critical); } +.dt-node--limited { background: var(--color-severity-medium); color: var(--color-severity-medium-on); } +.dt-node--minimal { background: var(--color-severity-low); } +.dt-row { display: flex; gap: var(--space-3); } + +/* TRAFFIC-LIGHTS */ +.traffic-light { + display: inline-flex; align-items: center; gap: 8px; + padding: 6px 12px; + border-radius: var(--radius-md); + background: var(--color-bg-soft); + border: 1px solid var(--color-border-subtle); + font-size: var(--font-size-sm); +} +.traffic-light__dot { + width: 10px; height: 10px; border-radius: 50%; + flex-shrink: 0; +} +.traffic-light[data-status="green"] .traffic-light__dot { background: var(--color-state-success); } +.traffic-light[data-status="yellow"] .traffic-light__dot { background: var(--color-severity-medium); } +.traffic-light[data-status="red"] .traffic-light__dot { background: var(--color-severity-critical); } +.traffic-light[data-status="gray"] .traffic-light__dot { background: var(--color-text-tertiary); } +.traffic-light__label { font-weight: var(--font-weight-medium); } +.traffic-light__why { color: var(--color-text-tertiary); font-size: var(--font-size-xs); } + +/* DIFF-REVIEW */ +.diff { border: 1px solid var(--color-border-subtle); border-radius: var(--radius-md); overflow: hidden; } +.diff__row { display: grid; grid-template-columns: 1fr 1fr; border-top: 1px solid var(--color-border-subtle); } +.diff__row:first-child { border-top: none; } +.diff__cell { padding: 10px 14px; font-size: var(--font-size-sm); font-family: var(--font-family-mono); } +.diff__cell--removed { background: var(--color-severity-critical-soft); color: var(--color-severity-critical-on); border-right: 1px solid var(--color-border-subtle); } +.diff__cell--added { background: var(--color-severity-low-soft); color: var(--color-severity-low-on); } +.diff__cell--unchanged { color: var(--color-text-secondary); border-right: 1px solid var(--color-border-subtle); } +.diff__summary { display: flex; gap: var(--space-4); padding: 12px 16px; background: var(--color-bg-soft); border-bottom: 1px solid var(--color-border-subtle); font-size: var(--font-size-sm); } +.diff__summary-item { display: flex; gap: 6px; align-items: baseline; } +.diff__summary-count { font-weight: var(--font-weight-semibold); font-variant-numeric: tabular-nums; } + +/* TREEMAP — pure CSS treemap with grid */ +.treemap { + display: grid; + grid-template-columns: repeat(12, 1fr); + grid-auto-rows: 36px; + gap: 2px; + background: var(--color-border-subtle); + border-radius: var(--radius-md); + overflow: hidden; + padding: 2px; +} +.treemap__tile { + padding: 8px 10px; + font-size: var(--font-size-xs); + display: flex; + flex-direction: column; + justify-content: space-between; + color: #fff; + overflow: hidden; + cursor: pointer; + position: relative; +} +.treemap__tile-label { font-weight: var(--font-weight-semibold); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.treemap__tile-tokens { font-family: var(--font-family-mono); font-size: 11px; opacity: 0.85; } +.treemap__tile[data-kind="claudemd"] { background: #4338CA; } +.treemap__tile[data-kind="plugin"] { background: #0F6E76; } +.treemap__tile[data-kind="skill"] { background: #9A6700; } +.treemap__tile[data-kind="mcp"] { background: #3F5963; } +.treemap__tile[data-kind="hook"] { background: #A40E26; } + +/* DISTRIBUTION / range-viz */ +.distribution { display: flex; flex-direction: column; gap: var(--space-3); } +.distribution__row { display: grid; grid-template-columns: 140px 1fr; gap: var(--space-3); align-items: center; font-size: var(--font-size-sm); } +.distribution__label { color: var(--color-text-secondary); } +.distribution__track { + position: relative; height: 28px; + background: var(--color-surface-sunken); + border-radius: var(--radius-sm); + overflow: visible; +} +.distribution__band { + position: absolute; top: 6px; bottom: 6px; + background: var(--color-primary-300); + border-radius: var(--radius-pill); + opacity: 0.4; +} +.distribution__median { + position: absolute; top: 0; bottom: 0; width: 2px; + background: var(--color-primary-700); +} +.distribution__median-label { + position: absolute; top: -18px; left: 50%; transform: translateX(-50%); + font-size: 11px; font-family: var(--font-family-mono); white-space: nowrap; + color: var(--color-text-primary); font-weight: var(--font-weight-semibold); +} +.distribution__axis { + display: grid; grid-template-columns: 140px 1fr; gap: var(--space-3); + font-size: 11px; color: var(--color-text-tertiary); font-family: var(--font-family-mono); + margin-top: 4px; +} +.distribution__axis-ticks { display: flex; justify-content: space-between; } + +/* COMMAND-PIPELINE OUTPUT */ +.cmd-pipeline { display: flex; flex-direction: column; gap: var(--space-2); } +.cmd-step { + display: grid; + grid-template-columns: 32px 1fr auto; + gap: var(--space-3); + padding: 12px 14px; + background: var(--color-surface-sunken); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-md); + align-items: center; +} +.cmd-step__num { + width: 24px; height: 24px; + border-radius: 50%; + background: var(--color-text-primary); + color: var(--color-bg); + display: flex; align-items: center; justify-content: center; + font-family: var(--font-family-mono); + font-size: 11px; font-weight: var(--font-weight-bold); +} +.cmd-step__cmd { + font-family: var(--font-family-mono); + font-size: var(--font-size-sm); + color: var(--color-text-primary); + word-break: break-all; +} +.cmd-step__cmd .cmd-flag { color: var(--color-state-info); } +.cmd-step__cmd .cmd-arg { color: var(--color-severity-medium-on); } + +/* PYRAMIDE — AI Act 4-tier */ +.pyramide { display: flex; flex-direction: column; align-items: center; gap: 4px; } +.pyramide__tier { + display: flex; align-items: center; justify-content: space-between; + padding: 10px 18px; + color: #fff; + font-weight: var(--font-weight-semibold); + font-size: var(--font-size-sm); + border-radius: var(--radius-sm); + width: 100%; +} +.pyramide__tier--forbidden { background: var(--color-severity-extreme); max-width: 30%; } +.pyramide__tier--high { background: var(--color-severity-critical); max-width: 50%; } +.pyramide__tier--limited { background: var(--color-severity-medium); color: var(--color-severity-medium-on); max-width: 75%; } +.pyramide__tier--minimal { background: var(--color-severity-low); max-width: 100%; } +.pyramide__tier-label { display: flex; gap: var(--space-2); align-items: center; } +.pyramide__tier-share { font-family: var(--font-family-mono); font-size: 11px; opacity: 0.85; } + +/* PIPELINE-COCKPIT */ +.pipeline-cockpit { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); + gap: 0; + align-items: stretch; + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-md); + overflow: hidden; + background: var(--color-surface); +} +.pc-stage { + padding: var(--space-3) var(--space-4); + border-right: 1px solid var(--color-border-subtle); + display: flex; flex-direction: column; gap: 4px; + position: relative; +} +.pc-stage:last-child { border-right: none; } +.pc-stage__num { font-family: var(--font-family-mono); font-size: 11px; color: var(--color-text-tertiary); } +.pc-stage__name { font-weight: var(--font-weight-semibold); font-size: var(--font-size-sm); } +.pc-stage__state { + font-size: 11px; padding: 2px 8px; border-radius: var(--radius-pill); + align-self: flex-start; margin-top: 4px; + font-weight: var(--font-weight-medium); +} +.pc-stage__state[data-state="done"] { background: var(--color-severity-low-soft); color: var(--color-severity-low-on); } +.pc-stage__state[data-state="running"] { background: var(--color-severity-medium-soft); color: var(--color-severity-medium-on); } +.pc-stage__state[data-state="empty"] { background: var(--color-bg-soft); color: var(--color-text-tertiary); } +.pc-stage__state[data-state="failed"] { background: var(--color-severity-critical); color: #fff; } +.pc-stage[data-current="true"] { background: var(--color-primary-50); } +[data-theme="dark"] .pc-stage[data-current="true"] { background: var(--color-primary-900); } + +/* VERDICT-PILL with risk-meter */ +.verdict-block { + display: grid; + grid-template-columns: auto 1fr; + gap: var(--space-6); + align-items: center; + padding: var(--space-5) var(--space-6); + background: var(--color-surface); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-lg); +} +.verdict-pill-lg { + display: flex; flex-direction: column; align-items: center; gap: 2px; + padding: var(--space-4) var(--space-5); + border-radius: var(--radius-md); + font-weight: var(--font-weight-bold); + letter-spacing: 0.04em; +} +.verdict-pill-lg__verdict { font-size: var(--font-size-xl); } +.verdict-pill-lg__sub { font-size: 11px; font-weight: var(--font-weight-medium); opacity: 0.8; text-transform: uppercase; letter-spacing: 0.1em; } +.verdict-pill-lg[data-verdict="block"] { background: var(--color-severity-critical); color: #fff; } +.verdict-pill-lg[data-verdict="warning"] { background: var(--color-severity-medium); color: var(--color-severity-medium-on); } +.verdict-pill-lg[data-verdict="allow"] { background: var(--color-severity-low); color: #fff; } + +.risk-meter { display: flex; flex-direction: column; gap: 6px; } +.risk-meter__track { + position: relative; + height: 12px; + background: linear-gradient(to right, + var(--color-severity-low) 0%, var(--color-severity-low) 14%, + var(--color-severity-medium) 14%, var(--color-severity-medium) 39%, + var(--color-severity-high) 39%, var(--color-severity-high) 64%, + var(--color-severity-critical) 64%, var(--color-severity-critical) 84%, + var(--color-severity-extreme) 84%, var(--color-severity-extreme) 100%); + border-radius: var(--radius-pill); +} +.risk-meter__pointer { + position: absolute; top: -4px; bottom: -4px; + width: 4px; + background: var(--color-text-primary); + border-radius: 2px; + box-shadow: 0 0 0 2px var(--color-bg); +} +.risk-meter__scale { + display: flex; justify-content: space-between; + font-size: 11px; color: var(--color-text-tertiary); + font-family: var(--font-family-mono); +} +.risk-meter__bands { + display: flex; justify-content: space-between; + font-size: 11px; color: var(--color-text-secondary); +} +.risk-meter__readout { + display: flex; align-items: baseline; gap: 8px; +} +.risk-meter__score { + font-size: var(--font-size-3xl); font-weight: var(--font-weight-bold); + font-variant-numeric: tabular-nums; + letter-spacing: -0.02em; +} +.risk-meter__band-label { font-size: var(--font-size-sm); color: var(--color-text-secondary); } + +/* CODEPOINT-REVEAL */ +.codepoint-reveal { background: var(--color-surface-sunken); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-md); overflow: hidden; } +.codepoint-reveal__head { padding: 10px 14px; background: var(--color-bg-soft); border-bottom: 1px solid var(--color-border-subtle); display: flex; justify-content: space-between; align-items: center; } +.codepoint-reveal__body { padding: var(--space-4); display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-4); } +.codepoint-reveal__col { display: flex; flex-direction: column; gap: 8px; } +.codepoint-reveal__col-label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--color-text-tertiary); font-weight: var(--font-weight-semibold); } +.codepoint-reveal__source { + font-family: var(--font-family-mono); + font-size: var(--font-size-sm); + padding: 12px; + background: var(--color-surface); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-sm); + min-height: 64px; + word-break: break-all; + white-space: pre-wrap; +} +.cp-tag { background: var(--color-severity-critical); color: #fff; padding: 1px 4px; border-radius: 2px; font-size: 11px; } +.cp-zw { background: var(--color-severity-medium); color: var(--color-severity-medium-on); padding: 1px 4px; border-radius: 2px; font-size: 11px; } +.cp-bidi { background: var(--color-severity-high); color: #fff; padding: 1px 4px; border-radius: 2px; font-size: 11px; } +.codepoint-reveal__decoded { + font-family: var(--font-family-mono); + font-size: var(--font-size-sm); + padding: 12px; + background: var(--color-text-primary); + color: var(--color-bg); + border-radius: var(--radius-sm); + word-break: break-all; +} + +/* SMALL-MULTIPLES GRID (16-category posture) */ +.small-multiples { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: var(--space-3); +} +.sm-card { + padding: var(--space-3); + background: var(--color-surface); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-md); + display: flex; flex-direction: column; gap: 6px; +} +.sm-card__header { display: flex; justify-content: space-between; align-items: baseline; } +.sm-card__name { font-size: var(--font-size-xs); font-weight: var(--font-weight-semibold); color: var(--color-text-secondary); text-transform: uppercase; letter-spacing: 0.04em; } +.sm-card__grade { + font-family: var(--font-family-mono); + font-size: var(--font-size-lg); + font-weight: var(--font-weight-bold); + width: 28px; height: 28px; + display: flex; align-items: center; justify-content: center; + border-radius: var(--radius-sm); +} +.sm-card__grade[data-grade="A"] { background: var(--color-severity-low); color: #fff; } +.sm-card__grade[data-grade="B"] { background: var(--color-severity-low-soft); color: var(--color-severity-low-on); } +.sm-card__grade[data-grade="C"] { background: var(--color-severity-medium-soft); color: var(--color-severity-medium-on); } +.sm-card__grade[data-grade="D"] { background: var(--color-severity-high-soft); color: var(--color-severity-high-on); } +.sm-card__grade[data-grade="F"] { background: var(--color-severity-critical); color: #fff; } +.sm-card__bar { height: 4px; background: var(--color-surface-sunken); border-radius: var(--radius-pill); overflow: hidden; } +.sm-card__bar-fill { height: 100%; background: var(--color-primary-500); } +.sm-card__status { font-size: 11px; color: var(--color-text-tertiary); } +@media (max-width: 880px) { .small-multiples { grid-template-columns: repeat(2, 1fr); } } + +/* OWASP badges (specific colors) */ +.badge--owasp-llm { background: #1F2328; color: #fff; } +.badge--owasp-asi { background: #4338CA; color: #fff; } +.badge--owasp-ast { background: #9A6700; color: #fff; } +.badge--owasp-mcp { background: #0F6E76; color: #fff; } diff --git a/plugins/ms-ai-architect/playground/vendor/playground-design-system/components-tier3-supplement.css b/plugins/ms-ai-architect/playground/vendor/playground-design-system/components-tier3-supplement.css new file mode 100644 index 0000000..00bbbb4 --- /dev/null +++ b/plugins/ms-ai-architect/playground/vendor/playground-design-system/components-tier3-supplement.css @@ -0,0 +1,887 @@ +/* Code generated by sync-design-system.mjs; DO NOT EDIT. */ +/* ============================================================================= + components-tier3-supplement.css + Tier 3 supplement — 12 components added after Tier 3 main set. + Pinned rules: + - No big pink fills for text. Use surface bg + colored border + dark body text. + - severity-critical (#A40E26) ≠ state-failed (#7D1A1A). Don't conflate. + - Light + dark theme via existing tokens only. + ============================================================================= */ + +/* ========================================================================= + 1. Sankey / Toxic-Flow Chain (.tfa-flow) + 3-step: Input → Access → Exfil with mitigation shields breaking the chain. + ========================================================================= */ +.tfa-flow { + display: grid; + grid-template-columns: 1fr auto 1fr auto 1fr; + gap: 0; + align-items: stretch; + background: var(--color-surface); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-lg); + padding: var(--space-5); + position: relative; +} +.tfa-flow__verdict { + position: absolute; + top: -12px; right: var(--space-5); + padding: 4px 10px; + font-size: 11px; + font-weight: var(--font-weight-bold); + letter-spacing: 0.06em; + border-radius: var(--radius-pill); + background: var(--color-severity-critical); + color: #fff; +} +.tfa-flow__verdict[data-verdict="ALLOW"] { background: var(--color-state-success); } +.tfa-flow__verdict[data-verdict="WARN"] { background: var(--color-severity-medium); color: #fff; } +.tfa-flow__verdict[data-verdict="BLOCK"] { background: var(--color-severity-critical); } + +.tfa-leg { + display: flex; flex-direction: column; gap: 6px; + padding: var(--space-3); + background: var(--color-surface); + border: 1px solid var(--color-border-subtle); + border-left-width: 4px; + border-radius: var(--radius-md); + cursor: pointer; + transition: background var(--duration-fast) var(--ease-default); + text-align: left; +} +.tfa-leg:hover { background: var(--color-bg-soft); } +.tfa-leg:focus-visible { outline: none; box-shadow: var(--shadow-focus); } +.tfa-leg[data-severity="medium"] { border-left-color: var(--color-severity-medium); } +.tfa-leg[data-severity="high"] { border-left-color: var(--color-severity-high); } +.tfa-leg[data-severity="critical"] { border-left-color: var(--color-severity-critical); } + +.tfa-leg__label { + font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; + color: var(--color-text-tertiary); font-weight: var(--font-weight-semibold); +} +.tfa-leg__name { font-size: var(--font-size-md); font-weight: var(--font-weight-semibold); color: var(--color-text-primary); } +.tfa-leg__source { font-family: var(--font-family-mono); font-size: 12px; color: var(--color-text-secondary); } +.tfa-leg__status { + margin-top: auto; + font-size: 11px; + font-weight: var(--font-weight-medium); + display: inline-flex; align-items: center; gap: 4px; +} +.tfa-leg__status[data-mit="unmitigated"] { color: var(--color-severity-critical); } +.tfa-leg__status[data-mit="partially_mitigated"] { color: var(--color-severity-medium); } +.tfa-leg__status[data-mit="mitigated"] { color: var(--color-state-success); } + +/* Arrow connectors. Width grows with severity */ +.tfa-arrow { + display: flex; align-items: center; justify-content: center; + position: relative; + min-width: 56px; + padding: 0 4px; +} +.tfa-arrow__line { + height: 4px; + width: 100%; + background: var(--color-border-moderate); + position: relative; +} +.tfa-arrow[data-severity="medium"] .tfa-arrow__line { background: var(--color-severity-medium); height: 6px; } +.tfa-arrow[data-severity="high"] .tfa-arrow__line { background: var(--color-severity-high); height: 8px; } +.tfa-arrow[data-severity="critical"] .tfa-arrow__line { background: var(--color-severity-critical); height: 10px; } +.tfa-arrow__line::after { + content: ""; position: absolute; right: -1px; top: 50%; + width: 0; height: 0; + border-left: 10px solid currentColor; + border-top: 8px solid transparent; + border-bottom: 8px solid transparent; + transform: translateY(-50%); + color: inherit; +} +.tfa-arrow[data-severity="medium"] .tfa-arrow__line { color: var(--color-severity-medium); } +.tfa-arrow[data-severity="high"] .tfa-arrow__line { color: var(--color-severity-high); } +.tfa-arrow[data-severity="critical"] .tfa-arrow__line { color: var(--color-severity-critical); } + +.tfa-arrow__shield { + position: absolute; + top: 50%; left: 50%; + transform: translate(-50%, -50%); + width: 32px; height: 32px; + background: var(--color-state-success); + color: #fff; + border-radius: 50%; + display: flex; align-items: center; justify-content: center; + border: 3px solid var(--color-surface); + font-size: 16px; +} +.tfa-arrow--mitigated .tfa-arrow__line { + background: repeating-linear-gradient(90deg, var(--color-state-success) 0 4px, transparent 4px 8px); +} + +@media (max-width: 720px) { + .tfa-flow { + grid-template-columns: 1fr; + grid-template-rows: auto auto auto auto auto; + } + .tfa-arrow { min-height: 48px; min-width: auto; } + .tfa-arrow__line { width: 4px; height: 100%; } + .tfa-arrow[data-severity="medium"] .tfa-arrow__line { width: 6px; height: 100%; } + .tfa-arrow[data-severity="high"] .tfa-arrow__line { width: 8px; height: 100%; } + .tfa-arrow[data-severity="critical"] .tfa-arrow__line { width: 10px; height: 100%; } + .tfa-arrow__line::after { + right: 50%; top: auto; bottom: -1px; transform: translateX(50%); + border-left: 8px solid transparent; + border-right: 8px solid transparent; + border-top: 10px solid currentColor; + border-bottom: none; + } +} + +/* ========================================================================= + 2. Fleet-Overview (.fleet-grid, .fleet-tile) + ========================================================================= */ +.fleet-toolbar { + display: flex; gap: var(--space-3); flex-wrap: wrap; + align-items: center; + padding: var(--space-3) var(--space-4); + background: var(--color-bg-soft); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-md); + margin-bottom: var(--space-3); +} +.fleet-toolbar__label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--color-text-tertiary); font-weight: var(--font-weight-semibold); } +.fleet-toolbar__spacer { flex: 1; } +.fleet-toolbar__count { font-size: var(--font-size-sm); color: var(--color-text-secondary); } + +.fleet-grid { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: var(--space-3); +} +@media (max-width: 980px) { .fleet-grid { grid-template-columns: repeat(2, 1fr); } } +@media (max-width: 540px) { .fleet-grid { grid-template-columns: 1fr; } } + +.fleet-tile { + background: var(--color-surface); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-md); + padding: var(--space-3); + display: grid; + grid-template-rows: auto auto auto auto; + gap: 6px; + cursor: pointer; + transition: border-color var(--duration-fast), transform var(--duration-fast); +} +.fleet-tile:hover { border-color: var(--color-primary-300); transform: translateY(-1px); } +.fleet-tile:focus-visible { outline: none; box-shadow: var(--shadow-focus); } + +.fleet-tile__row { display: flex; justify-content: space-between; align-items: center; gap: 8px; } +.fleet-tile__name { + font-family: var(--font-family-mono); + font-size: 12px; + color: var(--color-text-primary); + white-space: nowrap; overflow: hidden; text-overflow: ellipsis; + flex: 1; +} +.fleet-tile__grade { + width: 28px; height: 28px; + display: flex; align-items: center; justify-content: center; + font-weight: var(--font-weight-bold); + font-size: 13px; + border-radius: var(--radius-sm); + color: #fff; + flex-shrink: 0; +} +.fleet-tile__grade[data-grade="A"] { background: var(--color-state-success); } +.fleet-tile__grade[data-grade="B"] { background: #4D8E2F; } +.fleet-tile__grade[data-grade="C"] { background: var(--color-severity-medium); } +.fleet-tile__grade[data-grade="D"] { background: var(--color-severity-high); } +.fleet-tile__grade[data-grade="E"] { background: var(--color-severity-critical); } +.fleet-tile__grade[data-grade="F"] { background: var(--color-severity-extreme); } + +.fleet-tile__meter { + height: 6px; border-radius: 3px; + background: var(--color-bg-soft); + overflow: hidden; + position: relative; +} +.fleet-tile__meter-fill { height: 100%; border-radius: 3px; } +.fleet-tile__meter-fill[data-band="1"] { background: var(--color-state-success); } +.fleet-tile__meter-fill[data-band="2"] { background: var(--color-severity-medium); } +.fleet-tile__meter-fill[data-band="3"] { background: var(--color-severity-high); } +.fleet-tile__meter-fill[data-band="4"] { background: var(--color-severity-critical); } + +.fleet-tile__chip { + display: inline-flex; align-items: center; + font-size: 11px; + padding: 2px 8px; + border-radius: var(--radius-pill); + background: var(--color-bg-soft); + color: var(--color-text-secondary); + border: 1px solid var(--color-border-subtle); + width: fit-content; +} +.fleet-tile__meta { + display: flex; justify-content: space-between; + font-size: 11px; color: var(--color-text-tertiary); + font-family: var(--font-family-mono); +} +.fleet-tile__trend--better { color: var(--color-state-success); } +.fleet-tile__trend--worse { color: var(--color-severity-critical); } +.fleet-tile__trend--stable { color: var(--color-text-tertiary); } + +/* ========================================================================= + 3. Kanban Keep / Review / Remove (.kanban-board) + ========================================================================= */ +.kanban-board { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: var(--space-4); +} +@media (max-width: 820px) { .kanban-board { grid-template-columns: 1fr; } } + +.kanban-col { + background: var(--color-bg-soft); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-md); + padding: var(--space-3); + display: flex; flex-direction: column; gap: var(--space-3); + min-height: 320px; +} +.kanban-col__head { + display: flex; align-items: center; justify-content: space-between; + padding-bottom: var(--space-2); + border-bottom: 2px solid var(--color-border-subtle); +} +.kanban-col[data-bucket="keep"] .kanban-col__head { border-bottom-color: var(--color-state-success); } +.kanban-col[data-bucket="review"] .kanban-col__head { border-bottom-color: var(--color-state-warning); } +.kanban-col[data-bucket="remove"] .kanban-col__head { border-bottom-color: var(--color-severity-critical); } + +.kanban-col__title { font-size: var(--font-size-md); font-weight: var(--font-weight-semibold); color: var(--color-text-primary); } +.kanban-col__count { + font-family: var(--font-family-mono); + font-size: 12px; + background: var(--color-surface); + padding: 2px 8px; + border-radius: var(--radius-pill); + color: var(--color-text-secondary); + border: 1px solid var(--color-border-subtle); +} + +.kanban-card { + background: var(--color-surface); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-md); + padding: var(--space-3); + cursor: grab; + display: flex; flex-direction: column; gap: 6px; + transition: box-shadow var(--duration-fast); +} +.kanban-card:hover { box-shadow: var(--shadow-md); } +.kanban-card[data-verdict="BLOCK"] { border-color: var(--color-severity-critical); border-left-width: 4px; } +.kanban-card[data-verdict="trusted"] { border-left: 4px solid var(--color-state-success); } +.kanban-card[data-verdict="unknown"] { border-left: 4px solid var(--color-state-warning); } + +.kanban-card__name { font-family: var(--font-family-mono); font-size: 13px; color: var(--color-text-primary); word-break: break-all; } +.kanban-card__meta { font-size: 11px; color: var(--color-text-tertiary); } +.kanban-card__reason { font-size: 12px; color: var(--color-text-secondary); } + +.kanban-col__empty { + margin: auto; + text-align: center; + color: var(--color-text-tertiary); + font-size: var(--font-size-sm); + padding: var(--space-4); +} +.kanban-col__empty button { margin-top: var(--space-2); } + +.kanban-actions { display: flex; gap: 4px; margin-top: 4px; } +.kanban-actions button { + flex: 1; font-size: 11px; padding: 4px 6px; + background: var(--color-bg-soft); border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-sm); color: var(--color-text-secondary); + cursor: pointer; font-family: inherit; +} +.kanban-actions button:hover { background: var(--color-surface-sunken); color: var(--color-text-primary); } + +/* ========================================================================= + 4. Maturity-Ladder (.mat-ladder) + ========================================================================= */ +.mat-ladder { + display: flex; flex-direction: column; + background: var(--color-surface); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-md); + padding: var(--space-4); + gap: 0; +} +.mat-step { + display: grid; + grid-template-columns: 56px 1fr; + gap: var(--space-4); + padding: var(--space-3) 0; + position: relative; +} +.mat-step + .mat-step { border-top: 1px dashed var(--color-border-subtle); } + +.mat-step__icon { + width: 44px; height: 44px; + border-radius: 50%; + display: flex; align-items: center; justify-content: center; + background: var(--color-surface); + border: 2px solid var(--color-border-moderate); + color: var(--color-text-tertiary); + font-weight: var(--font-weight-semibold); + font-size: 15px; + position: relative; + z-index: 1; +} +.mat-step[data-state="completed"] .mat-step__icon { + background: var(--color-state-success); + border-color: var(--color-state-success); + color: #fff; +} +.mat-step[data-state="current"] .mat-step__icon { + border-color: var(--color-primary-500); + color: var(--color-primary-700); + background: var(--color-surface); +} + +/* progress ring around current step */ +.mat-step__ring { + position: absolute; + inset: -4px; + border-radius: 50%; + pointer-events: none; +} +.mat-step__ring svg { width: 100%; height: 100%; transform: rotate(-90deg); } +.mat-step__ring circle { fill: none; stroke-width: 3; } +.mat-step__ring .ring-bg { stroke: var(--color-border-subtle); } +.mat-step__ring .ring-fill { stroke: var(--color-primary-500); } + +.mat-step__name { + font-size: var(--font-size-md); + font-weight: var(--font-weight-semibold); + color: var(--color-text-primary); + display: flex; align-items: center; gap: 8px; +} +.mat-step[data-state="completed"] .mat-step__name { color: var(--color-text-secondary); } +.mat-step[data-state="future"] .mat-step__name { color: var(--color-text-tertiary); } + +.mat-step__pill { + font-size: 11px; padding: 2px 8px; border-radius: var(--radius-pill); + text-transform: uppercase; letter-spacing: 0.06em; font-weight: var(--font-weight-semibold); +} +.mat-step__pill--current { background: var(--color-primary-100); color: var(--color-primary-700); } +.mat-step__pill--complete { background: transparent; color: var(--color-state-success); border: 1px solid currentColor; } + +.mat-step__desc { + font-size: var(--font-size-sm); + color: var(--color-text-secondary); + margin-top: 2px; + max-width: 60ch; +} + +.mat-step__progress { + margin-top: 6px; + display: flex; align-items: center; gap: 8px; + font-size: 12px; color: var(--color-text-tertiary); +} +.mat-step__progress-bar { + flex: 1; height: 4px; + background: var(--color-bg-soft); + border-radius: 2px; + overflow: hidden; + max-width: 200px; +} +.mat-step__progress-fill { height: 100%; background: var(--color-primary-500); border-radius: 2px; } + +/* ========================================================================= + 5. Classify-and-Transform / 5-Bucket-Sorter (.cls-sorter) + ========================================================================= */ +.cls-sorter { display: flex; flex-direction: column; gap: var(--space-4); } + +.cls-input { + background: var(--color-surface); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-md); + padding: var(--space-3); +} +.cls-input textarea { + width: 100%; min-height: 100px; + font-family: var(--font-family-sans); + font-size: var(--font-size-sm); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-sm); + padding: var(--space-2) var(--space-3); + background: var(--color-bg); + color: var(--color-text-primary); + resize: vertical; +} +.cls-input textarea:focus { outline: none; box-shadow: var(--shadow-focus); border-color: var(--color-border-focus); } + +.cls-buckets { + display: grid; + grid-template-columns: repeat(5, 1fr); + gap: var(--space-3); +} +@media (max-width: 1100px) { .cls-buckets { grid-template-columns: repeat(3, 1fr); } } +@media (max-width: 720px) { .cls-buckets { grid-template-columns: repeat(2, 1fr); } } +@media (max-width: 460px) { .cls-buckets { grid-template-columns: 1fr; } } + +.cls-bucket { + background: var(--color-surface); + border: 1px solid var(--color-border-subtle); + border-top-width: 4px; + border-radius: var(--radius-md); + padding: var(--space-3); + display: flex; flex-direction: column; gap: var(--space-2); + min-height: 200px; +} +.cls-bucket[data-egnethet="lav"] { border-top-color: var(--color-text-tertiary); } +.cls-bucket[data-egnethet="medium"] { border-top-color: var(--color-state-info); } +.cls-bucket[data-egnethet="hoy"] { border-top-color: var(--color-state-success); } + +.cls-bucket__head { + display: flex; flex-direction: column; gap: 2px; + padding-bottom: var(--space-2); + border-bottom: 1px solid var(--color-border-subtle); +} +.cls-bucket__title { font-size: var(--font-size-sm); font-weight: var(--font-weight-semibold); color: var(--color-text-primary); } +.cls-bucket__egnethet { + font-size: 10px; text-transform: uppercase; letter-spacing: 0.08em; + color: var(--color-text-tertiary); font-weight: var(--font-weight-semibold); +} +.cls-bucket[data-egnethet="lav"] .cls-bucket__egnethet { color: var(--color-text-tertiary); } +.cls-bucket[data-egnethet="medium"] .cls-bucket__egnethet { color: var(--color-state-info); } +.cls-bucket[data-egnethet="hoy"] .cls-bucket__egnethet { color: var(--color-state-success); } + +.cls-item { + background: var(--color-bg-soft); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-sm); + padding: 6px 8px; + font-size: 12px; + color: var(--color-text-primary); + cursor: grab; + display: flex; flex-direction: column; gap: 2px; +} +.cls-item__action { + font-size: 10px; text-transform: uppercase; letter-spacing: 0.06em; + color: var(--color-text-tertiary); font-weight: var(--font-weight-medium); +} +.cls-bucket__action { + margin-top: auto; + padding-top: var(--space-2); + border-top: 1px dashed var(--color-border-subtle); +} +.cls-bucket__empty { + font-size: 12px; color: var(--color-text-tertiary); + font-style: italic; + text-align: center; + padding: var(--space-3); +} + +/* ========================================================================= + 6. Cycle Position Ribbon (.cycle-ribbon) + ========================================================================= */ +.cycle-ribbon { + position: relative; + background: var(--color-surface); + border-bottom: 1px solid var(--color-border-subtle); + padding: 8px var(--space-5); + display: flex; align-items: center; gap: var(--space-4); + font-size: 13px; + cursor: pointer; + overflow: hidden; +} +.cycle-ribbon::before { + content: ""; position: absolute; inset: 0; + background: var(--color-state-info); + opacity: 0.06; + width: var(--cycle-progress, 0%); + transition: width var(--duration-normal); +} +.cycle-ribbon[data-phase="planning"] { border-bottom-color: var(--color-state-info); } +.cycle-ribbon[data-phase="planning"]::before { background: var(--color-state-info); } +.cycle-ribbon[data-phase="execution"] { border-bottom-color: var(--color-state-success); } +.cycle-ribbon[data-phase="execution"]::before { background: var(--color-state-success); } +.cycle-ribbon[data-phase="retrospective_prep"] { border-bottom-color: var(--color-severity-medium); } +.cycle-ribbon[data-phase="retrospective_prep"]::before { background: var(--color-severity-medium); } + +.cycle-ribbon > * { position: relative; z-index: 1; } +.cycle-ribbon__id { font-family: var(--font-family-mono); font-weight: var(--font-weight-semibold); color: var(--color-text-primary); white-space: nowrap; flex-shrink: 0; } +.cycle-ribbon__week { color: var(--color-text-secondary); font-family: var(--font-family-mono); white-space: nowrap; flex-shrink: 0; } +.cycle-ribbon__phase { + font-size: 11px; padding: 2px 8px; + border-radius: var(--radius-pill); + text-transform: uppercase; letter-spacing: 0.06em; + font-weight: var(--font-weight-semibold); + white-space: nowrap; flex-shrink: 0; +} +.cycle-ribbon[data-phase="planning"] .cycle-ribbon__phase { background: var(--color-primary-100); color: var(--color-primary-700); } +.cycle-ribbon[data-phase="execution"] .cycle-ribbon__phase { background: var(--color-severity-low-soft); color: var(--color-severity-low-on); } +.cycle-ribbon[data-phase="retrospective_prep"] .cycle-ribbon__phase { background: var(--color-severity-medium-soft); color: var(--color-severity-medium-on); } +.cycle-ribbon__msg { color: var(--color-text-secondary); flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.cycle-ribbon__chev { color: var(--color-text-tertiary); transition: transform var(--duration-fast); } +.cycle-ribbon[aria-expanded="true"] .cycle-ribbon__chev { transform: rotate(180deg); } + +.cycle-ribbon__panel { + background: var(--color-bg-soft); + border-bottom: 1px solid var(--color-border-subtle); + padding: var(--space-4) var(--space-5); + display: none; + font-size: var(--font-size-sm); +} +.cycle-ribbon__panel[data-open="true"] { display: block; } + +@media (max-width: 720px) { + .cycle-ribbon__msg { display: none; } +} + +/* ========================================================================= + 7. Persistent-Antipattern Badge (.pap-badge) + ========================================================================= */ +.pap-badge { + display: inline-flex; align-items: center; gap: 6px; + padding: 4px 10px; + background: var(--color-surface); + border: 1px solid var(--color-severity-critical); + border-radius: var(--radius-pill); + font-size: 12px; + font-weight: var(--font-weight-medium); + color: var(--color-severity-critical); + cursor: pointer; + position: relative; +} +.pap-badge::before { + content: ""; + width: 8px; height: 8px; + border-radius: 50%; + background: var(--color-severity-critical); + animation: pap-pulse 2.4s var(--ease-default) infinite; +} +@keyframes pap-pulse { + 0%, 100% { opacity: 1; transform: scale(1); } + 50% { opacity: 0.45; transform: scale(0.7); } +} +@media (prefers-reduced-motion: reduce) { + .pap-badge::before { animation: none; opacity: 1; } +} +.pap-badge__count { font-family: var(--font-family-mono); font-weight: var(--font-weight-semibold); } + +.pap-detail { + margin-top: var(--space-3); + background: var(--color-surface); + border: 1px solid var(--color-severity-critical); + border-left-width: 4px; + border-radius: var(--radius-md); + padding: var(--space-4); + display: none; +} +.pap-detail[data-open="true"] { display: block; } +.pap-detail h4 { margin: 0 0 4px; color: var(--color-severity-critical); font-size: var(--font-size-md); } +.pap-detail__cycles { display: flex; gap: 4px; flex-wrap: wrap; margin: var(--space-2) 0; } +.pap-detail__cycle { + font-family: var(--font-family-mono); + font-size: 11px; + padding: 2px 6px; + background: var(--color-bg-soft); + border-radius: var(--radius-sm); + color: var(--color-text-secondary); +} +.pap-detail__rec { + background: var(--color-bg-soft); + border-radius: var(--radius-sm); + padding: var(--space-2) var(--space-3); + margin-top: var(--space-2); + font-size: var(--font-size-sm); + color: var(--color-text-primary); +} + +/* one-shot variant */ +.pap-badge--oneshot { + border-style: dashed; + border-color: var(--color-severity-medium); + color: var(--color-severity-medium); +} +.pap-badge--oneshot::before { display: none; } + +/* ========================================================================= + 8. Suppressed-Signals Panel (.suppressed) + ========================================================================= */ +.suppressed { + background: var(--color-bg-soft); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-md); + overflow: hidden; +} +.suppressed__head { + width: 100%; + display: flex; align-items: center; gap: var(--space-3); + padding: var(--space-3) var(--space-4); + background: transparent; + border: 0; + cursor: pointer; + font-family: inherit; + text-align: left; + color: var(--color-text-secondary); +} +.suppressed__head:hover { background: var(--color-surface-sunken); color: var(--color-text-primary); } +.suppressed__head:focus-visible { outline: none; box-shadow: var(--shadow-focus); } +.suppressed__chev { color: var(--color-text-tertiary); transition: transform var(--duration-fast); } +.suppressed[aria-expanded="true"] .suppressed__chev { transform: rotate(90deg); } +.suppressed__label { font-size: var(--font-size-sm); } +.suppressed__count { + font-family: var(--font-family-mono); + font-size: 12px; + background: var(--color-surface); + padding: 2px 8px; + border-radius: var(--radius-pill); + color: var(--color-text-secondary); + border: 1px solid var(--color-border-subtle); + margin-left: auto; +} + +.suppressed__body { + display: none; + padding: 0 var(--space-4) var(--space-4); +} +.suppressed[aria-expanded="true"] .suppressed__body { display: block; } + +.suppressed-group { + background: var(--color-surface); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-sm); + padding: var(--space-3); +} +.suppressed-group + .suppressed-group { margin-top: var(--space-2); } +.suppressed-group__head { + display: flex; justify-content: space-between; align-items: center; gap: 8px; + margin-bottom: 4px; +} +.suppressed-group__reason { font-family: var(--font-family-mono); font-size: 12px; color: var(--color-text-tertiary); } +.suppressed-group__count { font-size: 11px; color: var(--color-text-tertiary); } +.suppressed-group__desc { font-size: var(--font-size-sm); color: var(--color-text-secondary); margin: 0 0 6px; } +.suppressed-group__examples { + display: flex; gap: 4px; flex-wrap: wrap; +} +.suppressed-group__example { + font-family: var(--font-family-mono); + font-size: 11px; + background: var(--color-bg-soft); + padding: 2px 6px; + border-radius: var(--radius-sm); + color: var(--color-text-secondary); +} + +/* ========================================================================= + 9. ExpansionCard (Aksel) (.expansion) + ========================================================================= */ +.expansion { + background: var(--color-surface); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-md); + overflow: hidden; +} +.expansion + .expansion { margin-top: var(--space-2); } +.expansion__head { + width: 100%; + display: flex; align-items: flex-start; gap: var(--space-3); + padding: var(--space-3) var(--space-4); + background: transparent; + border: 0; + cursor: pointer; + font-family: inherit; + text-align: left; +} +.expansion__head:hover { background: var(--color-bg-soft); } +.expansion__head:focus-visible { outline: none; box-shadow: var(--shadow-focus); } +.expansion__title { flex: 1; } +.expansion__title-main { font-size: var(--font-size-md); color: var(--color-text-primary); font-weight: var(--font-weight-medium); } +.expansion__title-sub { font-size: var(--font-size-sm); color: var(--color-text-secondary); margin-top: 2px; } +.expansion__chev { + color: var(--color-text-tertiary); + transition: transform var(--duration-normal) var(--ease-default); + flex-shrink: 0; + margin-top: 2px; +} +.expansion[aria-expanded="true"] .expansion__chev { transform: rotate(180deg); } + +.expansion__body { + display: grid; + grid-template-rows: 0fr; + transition: grid-template-rows var(--duration-normal) var(--ease-default); +} +.expansion[aria-expanded="true"] .expansion__body { grid-template-rows: 1fr; } +.expansion__body-inner { overflow: hidden; } +.expansion__body-inner > div { + padding: 0 var(--space-4) var(--space-4); + border-top: 1px solid var(--color-border-subtle); + padding-top: var(--space-3); + margin-top: -1px; +} +@media (prefers-reduced-motion: reduce) { + .expansion__body { transition: none; } +} + +/* ========================================================================= + 10. ReadMore (Aksel) (.read-more) + ========================================================================= */ +.read-more { + display: inline; +} +.read-more__trigger { + display: inline-flex; align-items: center; gap: 4px; + background: transparent; + border: 0; + color: var(--color-text-link); + font-family: inherit; + font-size: inherit; + font-weight: var(--font-weight-medium); + cursor: pointer; + padding: 0; + text-decoration: underline; + text-decoration-thickness: 1px; + text-underline-offset: 3px; +} +.read-more__trigger:hover { color: var(--color-text-link-hover); } +.read-more__trigger:focus-visible { outline: none; box-shadow: var(--shadow-focus); border-radius: 2px; } +.read-more__chev { transition: transform var(--duration-fast); } +.read-more[aria-expanded="true"] .read-more__chev { transform: rotate(180deg); } +.read-more__body { display: none; margin-top: var(--space-2); } +.read-more[aria-expanded="true"] .read-more__body { display: block; } + +/* ========================================================================= + 11. FormProgress (Aksel multi-step skjema) (.form-progress) + ========================================================================= */ +.form-progress { + background: var(--color-surface); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-md); + padding: var(--space-4); + display: flex; flex-direction: column; gap: var(--space-3); + width: 280px; + position: sticky; + top: var(--space-4); +} +.form-progress__autosave { + display: flex; align-items: center; gap: 6px; + font-size: 12px; + color: var(--color-text-tertiary); + padding-bottom: var(--space-2); + border-bottom: 1px solid var(--color-border-subtle); +} +.form-progress__autosave-dot { + width: 6px; height: 6px; + border-radius: 50%; + background: var(--color-state-success); +} +.form-progress__steps { display: flex; flex-direction: column; gap: 2px; } +.fp-step { + display: grid; + grid-template-columns: 28px 1fr; + gap: var(--space-2); + align-items: start; + padding: 8px; + border-radius: var(--radius-sm); + text-align: left; + background: transparent; + border: 0; + cursor: pointer; + font-family: inherit; + position: relative; +} +.fp-step:hover { background: var(--color-bg-soft); } +.fp-step:focus-visible { outline: none; box-shadow: var(--shadow-focus); } +.fp-step[disabled] { cursor: not-allowed; opacity: 0.5; } + +.fp-step__num { + width: 22px; height: 22px; + border-radius: 50%; + display: flex; align-items: center; justify-content: center; + background: var(--color-surface); + border: 1.5px solid var(--color-border-moderate); + color: var(--color-text-tertiary); + font-size: 11px; + font-weight: var(--font-weight-semibold); +} +.fp-step[data-state="done"] .fp-step__num { + background: var(--color-state-success); + border-color: var(--color-state-success); + color: #fff; +} +.fp-step[data-state="in-progress"] .fp-step__num { + border-color: var(--color-primary-500); + color: var(--color-primary-700); + font-weight: var(--font-weight-bold); +} +.fp-step__name { font-size: var(--font-size-sm); color: var(--color-text-primary); font-weight: var(--font-weight-medium); } +.fp-step[data-state="done"] .fp-step__name { color: var(--color-text-secondary); font-weight: var(--font-weight-regular); } +.fp-step[data-state="in-progress"] .fp-step__name { color: var(--color-primary-700); font-weight: var(--font-weight-semibold); } + +.fp-step__progress { + margin-top: 4px; + font-size: 11px; + color: var(--color-text-tertiary); + display: flex; align-items: center; gap: 6px; +} +.fp-step__bar { + flex: 1; height: 3px; + background: var(--color-bg-soft); + border-radius: 2px; overflow: hidden; + max-width: 80px; +} +.fp-step__bar-fill { height: 100%; background: var(--color-primary-500); } + +.form-progress__remaining { + padding-top: var(--space-2); + border-top: 1px solid var(--color-border-subtle); + font-size: 12px; color: var(--color-text-tertiary); + display: flex; justify-content: space-between; +} + +/* ========================================================================= + 12. Aspirational vs Committed Visual (.okr-mode) + Modifier added to OKR Objective cards + ========================================================================= */ +.okr-mode { + position: relative; + background: var(--color-surface); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-md); + padding: var(--space-4); +} +.okr-mode__gauge { + position: relative; + width: 88px; height: 88px; + display: flex; align-items: center; justify-content: center; + flex-shrink: 0; +} +.okr-mode__gauge svg { position: absolute; inset: 0; transform: rotate(-90deg); width: 100%; height: 100%; } +.okr-mode__gauge circle.gauge-bg { fill: none; stroke: var(--color-border-subtle); stroke-width: 6; } +.okr-mode__gauge circle.gauge-fill { fill: none; stroke: var(--color-state-success); stroke-width: 6; stroke-linecap: round; } +.okr-mode__gauge .gauge-value { font-family: var(--font-family-mono); font-size: 22px; font-weight: var(--font-weight-bold); color: var(--color-text-primary); position: relative; z-index: 1; } + +/* aspirational variant — dashed stroke */ +.okr-mode[data-mode="aspirational"] .okr-mode__gauge circle.gauge-fill { + stroke: var(--color-scope-okr); + stroke-dasharray: 6 4; +} +.okr-mode__badge { + position: absolute; + top: var(--space-2); right: var(--space-2); + font-size: 10px; font-weight: var(--font-weight-bold); letter-spacing: 0.08em; + padding: 2px 8px; + border-radius: var(--radius-sm); +} +.okr-mode[data-mode="aspirational"] .okr-mode__badge { + background: transparent; + color: var(--color-scope-okr); + border: 1px dashed var(--color-scope-okr); +} +.okr-mode[data-mode="committed"] .okr-mode__badge { + background: var(--color-primary-700); + color: #fff; +} +.okr-mode__row { display: flex; gap: var(--space-4); align-items: center; } +.okr-mode__objective { font-size: var(--font-size-md); color: var(--color-text-primary); flex: 1; } +.okr-mode__hint { font-size: 12px; color: var(--color-text-tertiary); margin-top: 4px; } diff --git a/plugins/ms-ai-architect/playground/vendor/playground-design-system/components-tier3.css b/plugins/ms-ai-architect/playground/vendor/playground-design-system/components-tier3.css new file mode 100644 index 0000000..11fb7c4 --- /dev/null +++ b/plugins/ms-ai-architect/playground/vendor/playground-design-system/components-tier3.css @@ -0,0 +1,717 @@ +/* Code generated by sync-design-system.mjs; DO NOT EDIT. */ +/* ============================================================================= + components-tier3.css — Tier 3 components (Phase 2) + Critical components for ms-ai-architect Playground v3 + universal Aksel patterns. + 19. Inherent + residual pair (before/after matrix transition) + 20. AI Act compliance-tidslinje (4-milepel timeline + countdown) + 21. 3-track entry (Guide/Explore/Expert — carried from Playground v2) + 22. FRIA rights-matrix (12 EU Charter rights × impact level) + 23. Capability-matrix (license × kapabilitet — available/cost/missing/conditional) + 24. Parallel-agent-status panel (multi-worker status grid) + 25. ErrorSummary (Aksel/GOV.UK form error pattern) + 26. GuidePanel (Aksel friendly inline guidance) + ============================================================================= */ + +/* ============================================================================= + 19. INHERENT + RESIDUAL PAIR + Used by: ROS (before/after mitigation), DPIA, AI Act mitigations, OKR check-ins + Pattern: two cells/scores side-by-side with arrow showing transition. + ============================================================================= */ +.pair-before-after { + display: grid; + grid-template-columns: 1fr auto 1fr; + gap: var(--space-4); + align-items: center; +} +.pair-before-after__cell { + background: var(--color-surface); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-md); + padding: var(--space-3) var(--space-4); + display: flex; + flex-direction: column; + gap: 4px; +} +.pair-before-after__cell-label { + font-size: var(--font-size-xs); + text-transform: uppercase; + letter-spacing: 0.06em; + color: var(--color-text-tertiary); + font-weight: var(--font-weight-semibold); +} +.pair-before-after__cell-value { + font-size: var(--font-size-2xl); + font-weight: var(--font-weight-bold); + font-variant-numeric: tabular-nums; + letter-spacing: -0.02em; + line-height: 1; +} +.pair-before-after__cell-meta { + font-size: var(--font-size-xs); + color: var(--color-text-secondary); +} +.pair-before-after__cell--severity-low { border-left: 4px solid var(--color-severity-low); } +.pair-before-after__cell--severity-medium { border-left: 4px solid var(--color-severity-medium); } +.pair-before-after__cell--severity-high { border-left: 4px solid var(--color-severity-high); } +.pair-before-after__cell--severity-critical { border-left: 4px solid var(--color-severity-critical); } +.pair-before-after__cell--severity-extreme { border-left: 4px solid var(--color-severity-extreme); } + +.pair-before-after__arrow { + display: flex; + align-items: center; + justify-content: center; + font-size: var(--font-size-2xl); + color: var(--color-text-tertiary); + line-height: 1; + user-select: none; +} +.pair-before-after__arrow::before { content: "→"; font-family: var(--font-family-sans); } +.pair-before-after__arrow--down::before { content: "↓"; } + +.pair-before-after__delta { + display: inline-flex; + align-items: baseline; + gap: 4px; + font-family: var(--font-family-mono); + font-size: var(--font-size-xs); + padding: 2px 8px; + border-radius: var(--radius-pill); + margin-top: 2px; +} +.pair-before-after__delta--improved { + background: var(--color-severity-low-soft); + color: var(--color-severity-low-on); +} +.pair-before-after__delta--worsened { + background: var(--color-severity-critical-soft); + color: var(--color-severity-critical-on); +} + +@media (max-width: 640px) { + .pair-before-after { grid-template-columns: 1fr; } + .pair-before-after__arrow { transform: rotate(90deg); } +} + +/* ============================================================================= + 20. AI ACT COMPLIANCE-TIDSLINJE + Horizontal timeline with 4 fixed EU AI Act milestones (2025-02-02, 2025-08-02, + 2026-08-02, 2027-08-02) plus a "today" marker and per-system countdown chips. + ============================================================================= */ +.aiact-timeline { + position: relative; + padding: var(--space-8) 0 var(--space-4); + margin: var(--space-4) 0; +} +.aiact-timeline__track { + position: relative; + height: 4px; + background: var(--color-border-subtle); + border-radius: var(--radius-pill); + margin: 0 12px; +} +.aiact-timeline__progress { + position: absolute; + top: 0; bottom: 0; left: 0; + background: var(--color-primary-500); + border-radius: var(--radius-pill); + /* width set inline based on today vs milestone span */ +} +.aiact-timeline__milestone { + position: absolute; + top: 50%; + transform: translate(-50%, -50%); + /* left set inline as percentage based on date span */ +} +.aiact-timeline__dot { + width: 16px; height: 16px; + border-radius: 50%; + background: var(--color-surface); + border: 3px solid var(--color-border-moderate); + cursor: pointer; + transition: transform var(--duration-fast) var(--ease-default), + border-color var(--duration-fast) var(--ease-default); +} +.aiact-timeline__dot:hover { transform: scale(1.15); } +.aiact-timeline__milestone[data-state="passed"] .aiact-timeline__dot { + background: var(--color-primary-500); + border-color: var(--color-primary-500); +} +.aiact-timeline__milestone[data-state="active"] .aiact-timeline__dot { + background: var(--color-severity-critical); + border-color: var(--color-severity-critical); + box-shadow: 0 0 0 4px var(--color-severity-critical-soft); +} +.aiact-timeline__milestone[data-state="upcoming"] .aiact-timeline__dot { + background: var(--color-surface); + border-color: var(--color-border-strong); +} + +.aiact-timeline__today { + position: absolute; + top: -6px; bottom: -6px; + width: 2px; + background: var(--color-text-primary); + /* left set inline based on current date */ +} +.aiact-timeline__today::after { + content: "I dag"; + position: absolute; + top: -22px; + left: 50%; + transform: translateX(-50%); + font-size: 10px; + font-family: var(--font-family-mono); + font-weight: var(--font-weight-semibold); + color: var(--color-text-primary); + background: var(--color-bg); + padding: 2px 6px; + border-radius: var(--radius-sm); + white-space: nowrap; +} + +.aiact-timeline__label { + position: absolute; + top: 22px; left: 50%; + transform: translateX(-50%); + text-align: center; + white-space: nowrap; + font-size: 11px; + font-family: var(--font-family-mono); + color: var(--color-text-secondary); +} +.aiact-timeline__label-date { font-weight: var(--font-weight-semibold); display: block; } +.aiact-timeline__label-name { color: var(--color-text-tertiary); display: block; margin-top: 1px; max-width: 140px; white-space: normal; line-height: 1.2; } + +.aiact-countdown { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 4px 10px; + font-size: var(--font-size-xs); + font-family: var(--font-family-mono); + border-radius: var(--radius-pill); + background: var(--color-bg-soft); + border: 1px solid var(--color-border-subtle); +} +.aiact-countdown__days { + font-weight: var(--font-weight-bold); + font-variant-numeric: tabular-nums; +} +.aiact-countdown[data-urgency="urgent"] { background: var(--color-severity-critical-soft); color: var(--color-severity-critical-on); border-color: transparent; } +.aiact-countdown[data-urgency="soon"] { background: var(--color-severity-medium-soft); color: var(--color-severity-medium-on); border-color: transparent; } +.aiact-countdown[data-urgency="distant"] { background: var(--color-severity-low-soft); color: var(--color-severity-low-on); border-color: transparent; } + +/* ============================================================================= + 21. 3-TRACK ENTRY (Guide / Explore / Expert) + Carried forward from Playground v2 — the most-validated UX pattern in our + fleet. Three large cards as the very first decision the user makes. + ============================================================================= */ +.tracks { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: var(--space-5); + margin: var(--space-8) 0; +} +.tracks__card { + display: flex; + flex-direction: column; + gap: var(--space-3); + padding: var(--space-6); + background: var(--color-surface); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-lg); + cursor: pointer; + transition: border-color var(--duration-fast) var(--ease-default), + transform var(--duration-fast) var(--ease-default), + box-shadow var(--duration-fast) var(--ease-default); + text-decoration: none; + color: inherit; + position: relative; + overflow: hidden; +} +.tracks__card::before { + content: ""; + position: absolute; + top: 0; left: 0; right: 0; + height: 4px; + background: var(--color-border-moderate); + transition: background var(--duration-fast) var(--ease-default); +} +.tracks__card:hover { + border-color: var(--color-border-strong); + transform: translateY(-2px); + box-shadow: var(--shadow-md); +} +.tracks__card--guided::before { background: var(--color-state-success); } +.tracks__card--explore::before { background: var(--color-primary-500); } +.tracks__card--expert::before { background: var(--color-text-primary); } + +.tracks__card-icon { + width: 40px; height: 40px; + border-radius: var(--radius-md); + background: var(--color-bg-soft); + display: flex; align-items: center; justify-content: center; + color: var(--color-text-secondary); +} +.tracks__card-title { + font-size: var(--font-size-lg); + font-weight: var(--font-weight-semibold); + margin: 0; +} +.tracks__card-desc { + font-size: var(--font-size-sm); + color: var(--color-text-secondary); + line-height: var(--line-height-snug); + margin: 0; +} +.tracks__card-meta { + margin-top: auto; + padding-top: var(--space-3); + display: flex; justify-content: space-between; align-items: baseline; + font-size: var(--font-size-xs); + color: var(--color-text-tertiary); + font-family: var(--font-family-mono); +} +.tracks__card-cta { + font-family: var(--font-family-sans); + font-weight: var(--font-weight-medium); + color: var(--color-text-primary); +} + +@media (max-width: 880px) { + .tracks { grid-template-columns: 1fr; } +} + +/* ============================================================================= + 22. FRIA RIGHTS-MATRIX + 12 EU Charter rights × impact level. Long left labels, compact right cells. + Each cell shows checkmark + severity color when right is impacted. + ============================================================================= */ +.rights-matrix { + display: grid; + grid-template-columns: 1fr; + gap: 1px; + background: var(--color-border-subtle); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-md); + overflow: hidden; +} +.rights-matrix__head, +.rights-matrix__row { + display: grid; + grid-template-columns: 1fr repeat(5, 64px); + background: var(--color-surface); +} +.rights-matrix__head { + background: var(--color-bg-soft); +} +.rights-matrix__head-cell, +.rights-matrix__name, +.rights-matrix__cell { + padding: 10px 12px; + font-size: var(--font-size-sm); + display: flex; + align-items: center; +} +.rights-matrix__head-cell { + font-size: var(--font-size-xs); + font-weight: var(--font-weight-semibold); + text-transform: uppercase; + letter-spacing: 0.04em; + color: var(--color-text-secondary); + justify-content: center; +} +.rights-matrix__head-cell--name { justify-content: flex-start; } +.rights-matrix__name { + font-weight: var(--font-weight-medium); + color: var(--color-text-primary); +} +.rights-matrix__name-meta { + display: block; + font-size: var(--font-size-xs); + color: var(--color-text-tertiary); + font-weight: var(--font-weight-regular); + margin-top: 2px; +} +.rights-matrix__cell { + justify-content: center; + font-family: var(--font-family-mono); + font-size: var(--font-size-sm); + font-weight: var(--font-weight-semibold); + font-variant-numeric: tabular-nums; + color: var(--color-text-tertiary); + border-left: 1px solid var(--color-border-subtle); +} +.rights-matrix__cell[data-impact="0"]::before { content: "—"; color: var(--color-text-tertiary); } +.rights-matrix__cell[data-impact="1"] { background: var(--color-severity-low-soft); color: var(--color-severity-low-on); } +.rights-matrix__cell[data-impact="2"] { background: var(--color-severity-medium-soft); color: var(--color-severity-medium-on); } +.rights-matrix__cell[data-impact="3"] { background: var(--color-severity-high-soft); color: var(--color-severity-high-on); } +.rights-matrix__cell[data-impact="4"] { background: var(--color-severity-critical-soft); color: var(--color-severity-critical-on); } +.rights-matrix__cell[data-impact="5"] { background: var(--color-severity-critical); color: var(--color-severity-critical-on); } + +@media (max-width: 720px) { + .rights-matrix__head, + .rights-matrix__row { grid-template-columns: 1fr repeat(5, 44px); } + .rights-matrix__head-cell, + .rights-matrix__cell { padding: 8px 6px; font-size: var(--font-size-xs); } +} + +/* ============================================================================= + 23. CAPABILITY-MATRIX + Rows = capabilities (e.g. "Generate text via M365 Chat"), columns = licenses + (E3, E5, Copilot, etc.). Cells use one of four states with explicit icon + + color so meaning never depends solely on color. + ============================================================================= */ +.capability-matrix { + display: grid; + gap: 1px; + background: var(--color-border-subtle); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-md); + overflow: hidden; + font-size: var(--font-size-sm); +} +.capability-matrix__head, +.capability-matrix__row { + display: grid; + background: var(--color-surface); + /* grid-template-columns set inline based on license count */ +} +.capability-matrix__head { background: var(--color-bg-soft); } +.capability-matrix__head-cell, +.capability-matrix__name, +.capability-matrix__cell { + padding: 10px 12px; + display: flex; + align-items: center; + gap: 6px; +} +.capability-matrix__head-cell { + font-size: var(--font-size-xs); + font-weight: var(--font-weight-semibold); + text-transform: uppercase; + letter-spacing: 0.04em; + color: var(--color-text-secondary); + justify-content: center; +} +.capability-matrix__head-cell--name { justify-content: flex-start; } +.capability-matrix__name { + font-weight: var(--font-weight-medium); + border-right: 1px solid var(--color-border-subtle); +} +.capability-matrix__cell { + justify-content: center; + font-family: var(--font-family-mono); + font-size: var(--font-size-md); + border-left: 1px solid var(--color-border-subtle); +} +.capability-matrix__cell-icon { + font-style: normal; + width: 22px; height: 22px; + display: inline-flex; + align-items: center; + justify-content: center; + border-radius: 50%; + font-size: 13px; + font-weight: var(--font-weight-bold); +} +.capability-matrix__cell[data-status="available"] { background: var(--color-severity-low-soft); } +.capability-matrix__cell[data-status="available"] .capability-matrix__cell-icon { background: var(--color-severity-low); color: #fff; } +.capability-matrix__cell[data-status="available"] .capability-matrix__cell-icon::before { content: "✓"; } +.capability-matrix__cell[data-status="cost"] { background: var(--color-severity-medium-soft); } +.capability-matrix__cell[data-status="cost"] .capability-matrix__cell-icon { background: var(--color-severity-medium); color: #fff; } +.capability-matrix__cell[data-status="cost"] .capability-matrix__cell-icon::before { content: "kr"; font-size: 10px; } +.capability-matrix__cell[data-status="conditional"] { background: var(--color-severity-high-soft); } +.capability-matrix__cell[data-status="conditional"] .capability-matrix__cell-icon { background: var(--color-severity-high); color: #fff; } +.capability-matrix__cell[data-status="conditional"] .capability-matrix__cell-icon::before { content: "!"; } +.capability-matrix__cell[data-status="missing"] { background: var(--color-bg-soft); } +.capability-matrix__cell[data-status="missing"] .capability-matrix__cell-icon { background: var(--color-text-tertiary); color: #fff; } +.capability-matrix__cell[data-status="missing"] .capability-matrix__cell-icon::before { content: "×"; } + +.capability-matrix__legend { + display: flex; + gap: var(--space-4); + flex-wrap: wrap; + font-size: var(--font-size-xs); + margin-top: var(--space-3); + color: var(--color-text-secondary); +} +.capability-matrix__legend-item { + display: inline-flex; + align-items: center; + gap: 6px; +} + +/* ============================================================================= + 24. PARALLEL-AGENT-STATUS PANEL + Used by ms-ai-architect utredning (4 parallel workers — security-worker, + cost-worker, dpia-worker, diagram-worker writing to .work/-files) and + ultraplan-local multi-wave execute. Grid of agent cards with state pills, + progress bars, and per-agent metrics. + ============================================================================= */ +.agent-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); + gap: var(--space-3); +} +.agent-card { + background: var(--color-surface); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-md); + padding: var(--space-4); + display: flex; + flex-direction: column; + gap: var(--space-2); + position: relative; +} +.agent-card__head { + display: flex; + justify-content: space-between; + align-items: flex-start; + gap: var(--space-2); +} +.agent-card__name { + font-weight: var(--font-weight-semibold); + font-size: var(--font-size-sm); + margin: 0; +} +.agent-card__role { + font-family: var(--font-family-mono); + font-size: 11px; + color: var(--color-text-tertiary); +} +.agent-card__state { + display: inline-flex; + align-items: center; + gap: 4px; + padding: 2px 8px; + font-size: 11px; + font-weight: var(--font-weight-medium); + border-radius: var(--radius-pill); + white-space: nowrap; +} +.agent-card__state[data-state="queued"] { background: var(--color-bg-soft); color: var(--color-text-tertiary); } +.agent-card__state[data-state="running"] { background: var(--color-severity-medium-soft); color: var(--color-severity-medium-on); } +.agent-card__state[data-state="done"] { background: var(--color-severity-low-soft); color: var(--color-severity-low-on); } +.agent-card__state[data-state="failed"] { background: var(--color-state-failed); color: #fff; } +.agent-card__state[data-state="blocked"] { background: var(--color-state-blocked); color: #fff; } +.agent-card__state-dot { + width: 6px; height: 6px; + border-radius: 50%; + background: currentColor; +} +.agent-card__state[data-state="running"] .agent-card__state-dot { + animation: agent-pulse 1.4s var(--ease-default) infinite; +} +@keyframes agent-pulse { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.35; } +} + +.agent-card__progress { + height: 4px; + background: var(--color-surface-sunken); + border-radius: var(--radius-pill); + overflow: hidden; +} +.agent-card__progress-fill { + height: 100%; + background: var(--color-primary-500); + transition: width var(--duration-normal) var(--ease-default); +} +.agent-card__metrics { + display: flex; + gap: var(--space-3); + font-size: var(--font-size-xs); + color: var(--color-text-secondary); +} +.agent-card__metric { display: flex; gap: 4px; align-items: baseline; } +.agent-card__metric-value { + font-variant-numeric: tabular-nums; + font-weight: var(--font-weight-semibold); + color: var(--color-text-primary); +} +.agent-card__output { + font-family: var(--font-family-mono); + font-size: 11px; + background: var(--color-surface-sunken); + padding: 6px 8px; + border-radius: var(--radius-sm); + max-height: 56px; + overflow: hidden; + color: var(--color-text-secondary); + white-space: pre-wrap; + word-break: break-word; +} +.agent-card__output::after { + content: ""; + position: absolute; + bottom: var(--space-4); + left: var(--space-4); + right: var(--space-4); + height: 18px; + background: linear-gradient(to bottom, transparent, var(--color-surface)); + pointer-events: none; +} + +/* ============================================================================= + 25. ERROR-SUMMARY (Aksel/GOV.UK pattern) + Concentrated list of validation errors at top of a form. Each error + anchor-links to the offending field. Required for accessible long forms. + ============================================================================= */ +.error-summary { + background: var(--color-surface); + border: 1px solid var(--color-severity-critical); + border-left-width: 4px; + border-radius: var(--radius-md); + padding: var(--space-4) var(--space-5); + display: flex; + flex-direction: column; + gap: var(--space-2); +} +.error-summary__heading { + display: flex; + align-items: center; + gap: 8px; + font-size: var(--font-size-md); + font-weight: var(--font-weight-semibold); + color: var(--color-severity-critical); + margin: 0; +} +[data-theme="dark"] .error-summary__heading { color: #F09095; } +.error-summary__heading::before { + content: "!"; + display: inline-flex; + align-items: center; + justify-content: center; + width: 20px; height: 20px; + border-radius: 50%; + background: var(--color-severity-critical); + color: #fff; + font-size: 14px; + font-weight: var(--font-weight-bold); + flex-shrink: 0; +} +.error-summary__body { + font-size: var(--font-size-sm); + color: var(--color-text-primary); + line-height: var(--line-height-snug); +} +.error-summary__list { + margin: var(--space-2) 0 0; + padding: 0 0 0 var(--space-5); + list-style: disc; + color: var(--color-text-primary); +} +.error-summary__item { margin-bottom: 4px; } +.error-summary__link { + color: var(--color-severity-critical); + text-decoration: underline; + text-underline-offset: 2px; + text-decoration-thickness: 1px; + font-weight: var(--font-weight-medium); +} +.error-summary__link:hover { text-decoration-thickness: 2px; color: var(--color-severity-extreme); } +[data-theme="dark"] .error-summary__link { color: #F09095; } +[data-theme="dark"] .error-summary__link:hover { color: #FFB7BA; } + +/* ============================================================================= + 26. GUIDE-PANEL (Aksel pattern) + Friendly inline guidance with optional illustration and CTA. Used to scaffold + first-time users through unfamiliar territory without scolding tone. + ============================================================================= */ +.guide-panel { + display: grid; + grid-template-columns: 56px 1fr auto; + gap: var(--space-4); + align-items: start; + background: var(--color-bg-soft); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-lg); + padding: var(--space-4) var(--space-5); +} +.guide-panel--info { background: #EAF3FB; border-color: rgba(9, 105, 218, 0.25); } +.guide-panel--success { background: var(--color-severity-low-soft); border-color: rgba(26, 127, 55, 0.3); } +.guide-panel--warn { background: var(--color-severity-medium-soft); border-color: rgba(191, 135, 0, 0.3); } +[data-theme="dark"] .guide-panel--info { background: #0E2A3F; border-color: rgba(111, 165, 221, 0.3); } + +.guide-panel__icon { + width: 56px; height: 56px; + border-radius: var(--radius-md); + background: var(--color-surface); + border: 1px solid var(--color-border-subtle); + display: flex; align-items: center; justify-content: center; + color: var(--color-primary-500); +} +.guide-panel--info .guide-panel__icon { color: var(--color-state-info); } +.guide-panel--success .guide-panel__icon { color: var(--color-state-success); } +.guide-panel--warn .guide-panel__icon { color: var(--color-severity-medium); } + +.guide-panel__body { + display: flex; + flex-direction: column; + gap: 4px; + min-width: 0; +} +.guide-panel__title { + font-size: var(--font-size-md); + font-weight: var(--font-weight-semibold); + margin: 0; + color: var(--color-text-primary); +} +.guide-panel__text { + font-size: var(--font-size-sm); + color: var(--color-text-secondary); + line-height: var(--line-height-snug); + margin: 0; + max-width: var(--measure); +} +.guide-panel__action { + align-self: center; + white-space: nowrap; +} +.guide-panel__dismiss { + position: absolute; + top: var(--space-2); + right: var(--space-2); + background: none; + border: none; + cursor: pointer; + width: 28px; height: 28px; + border-radius: var(--radius-sm); + display: flex; align-items: center; justify-content: center; + color: var(--color-text-tertiary); + font-family: inherit; +} +.guide-panel__dismiss:hover { background: rgba(0,0,0,0.06); color: var(--color-text-primary); } + +@media (max-width: 640px) { + .guide-panel { + grid-template-columns: 40px 1fr; + gap: var(--space-3); + } + .guide-panel__icon { width: 40px; height: 40px; } + .guide-panel__action { + grid-column: 1 / -1; + align-self: stretch; + } +} + +/* ============================================================================= + Print rules for Tier 3 + ============================================================================= */ +@media print { + .pair-before-after { page-break-inside: avoid; } + .aiact-timeline { page-break-inside: avoid; } + .agent-grid { page-break-inside: avoid; } + .tracks { display: none; } /* entry choice = screen-only */ + .guide-panel__dismiss { display: none; } /* dismiss only meaningful on screen */ + .error-summary { + background: #FFF !important; + border: 1pt solid #000 !important; + color: #000 !important; + } + .error-summary__heading, + .error-summary__body, + .error-summary__link { color: #000 !important; } +} diff --git a/plugins/ms-ai-architect/playground/vendor/playground-design-system/components.css b/plugins/ms-ai-architect/playground/vendor/playground-design-system/components.css new file mode 100644 index 0000000..fb5ea58 --- /dev/null +++ b/plugins/ms-ai-architect/playground/vendor/playground-design-system/components.css @@ -0,0 +1,650 @@ +/* Code generated by sync-design-system.mjs; DO NOT EDIT. */ +/* ============================================================================= + components.css — Tier 1 components (Phase 1) + 1. Radar / Spider + 2. Matrix / Heatmap (5x5 ROS) + 3. Findings-browser + 4. Critique-card + 5. Wizard / Stepper + 6. Live-meter / Quality-validator + ============================================================================= */ + +/* ============================================================================= + 1. RADAR + ============================================================================= */ +.radar { + display: grid; + grid-template-columns: 1fr 240px; + gap: var(--space-6); + align-items: start; +} +.radar__chart { + position: relative; + width: 100%; + aspect-ratio: 1 / 1; + max-width: 460px; +} +.radar__svg { width: 100%; height: 100%; display: block; overflow: visible; } +.radar__grid-line { fill: none; stroke: var(--color-border-subtle); stroke-width: 1; } +.radar__axis { stroke: var(--color-border-moderate); stroke-width: 1; } +.radar__label { + font-family: var(--font-family-sans); + font-size: 12px; + font-weight: var(--font-weight-medium); + fill: var(--color-text-secondary); + text-anchor: middle; +} +.radar__tick { font-size: 10px; fill: var(--color-text-tertiary); } +.radar__series { + fill: var(--color-primary-500); + fill-opacity: 0.18; + stroke: var(--color-primary-500); + stroke-width: 2; + stroke-linejoin: round; +} +.radar__series--target { + fill: none; + stroke: var(--color-text-tertiary); + stroke-width: 1.5; + stroke-dasharray: 4 4; +} +.radar__point { fill: var(--color-primary-500); r: 4; } +.radar__point--target { fill: var(--color-bg); stroke: var(--color-text-tertiary); stroke-width: 1.5; r: 3; } + +.radar__legend { display: flex; flex-direction: column; gap: var(--space-3); font-size: var(--font-size-sm); } +.radar__legend-item { display: flex; align-items: baseline; gap: var(--space-2); } +.radar__legend-swatch { width: 12px; height: 12px; border-radius: 2px; flex-shrink: 0; transform: translateY(1px); } +.radar__legend-swatch--current { background: var(--color-primary-500); } +.radar__legend-swatch--target { + background: transparent; + border: 1.5px dashed var(--color-text-tertiary); +} +.radar__scores { + margin-top: var(--space-4); + border-top: 1px solid var(--color-border-subtle); + padding-top: var(--space-3); + display: grid; + gap: 4px; +} +.radar__score-row { display: flex; justify-content: space-between; font-size: var(--font-size-xs); } +.radar__score-row dt { color: var(--color-text-secondary); } +.radar__score-row dd { margin: 0; font-variant-numeric: tabular-nums; font-weight: var(--font-weight-medium); } + +@media (max-width: 720px) { + .radar { grid-template-columns: 1fr; } +} + +/* ============================================================================= + 2. MATRIX / HEATMAP (5x5 ROS) + ============================================================================= */ +.matrix { + display: grid; + grid-template-columns: auto 1fr; + gap: var(--space-3); +} +.matrix__y-label { + writing-mode: vertical-rl; + transform: rotate(180deg); + text-align: center; + font-size: var(--font-size-sm); + font-weight: var(--font-weight-semibold); + color: var(--color-text-secondary); + letter-spacing: 0.06em; + text-transform: uppercase; + align-self: stretch; + display: flex; + align-items: center; + justify-content: center; +} +.matrix__main { display: flex; flex-direction: column; gap: var(--space-2); } +.matrix__grid { + display: grid; + grid-template-columns: 32px repeat(5, 1fr); + grid-template-rows: repeat(5, 1fr) 32px; + gap: 4px; + aspect-ratio: 5 / 5; + width: 100%; +} +.matrix__y-tick { + display: flex; align-items: center; justify-content: center; + font-size: var(--font-size-sm); font-weight: var(--font-weight-semibold); + color: var(--color-text-secondary); + font-variant-numeric: tabular-nums; +} +.matrix__x-tick { + display: flex; align-items: center; justify-content: center; + font-size: var(--font-size-sm); font-weight: var(--font-weight-semibold); + color: var(--color-text-secondary); + font-variant-numeric: tabular-nums; +} +.matrix__corner { /* empty bottom-left */ } +.matrix__cell { + position: relative; + display: flex; + align-items: center; + justify-content: center; + border-radius: var(--radius-sm); + cursor: pointer; + border: 1px solid transparent; + transition: transform var(--duration-fast) var(--ease-default), + box-shadow var(--duration-fast) var(--ease-default); + min-height: 64px; + background: var(--color-severity-low-soft); +} +.matrix__cell:hover { transform: scale(1.02); box-shadow: var(--shadow-md); z-index: 2; } +.matrix__cell[aria-selected="true"] { + outline: 3px solid var(--color-primary-500); + outline-offset: 2px; + z-index: 3; +} + +/* Severity zones based on score (sannsynlighet × konsekvens, 1-25) */ +.matrix__cell[data-score="1"], +.matrix__cell[data-score="2"], +.matrix__cell[data-score="3"], +.matrix__cell[data-score="4"] { background: var(--color-severity-low-soft); } +.matrix__cell[data-score="5"], +.matrix__cell[data-score="6"], +.matrix__cell[data-score="8"] { background: var(--color-severity-low-soft); } +.matrix__cell[data-score="9"], +.matrix__cell[data-score="10"], +.matrix__cell[data-score="12"] { background: var(--color-severity-medium-soft); } +.matrix__cell[data-score="15"], +.matrix__cell[data-score="16"] { background: var(--color-severity-high-soft); } +.matrix__cell[data-score="20"], +.matrix__cell[data-score="25"] { background: var(--color-severity-critical-soft); } + +.matrix__cell-score { + position: absolute; + top: 4px; + left: 6px; + font-size: 11px; + font-weight: var(--font-weight-semibold); + color: var(--color-text-tertiary); + font-variant-numeric: tabular-nums; +} +.matrix__cell-bubbles { + display: flex; + flex-wrap: wrap; + gap: 3px; + align-items: center; + justify-content: center; + padding: 12px 6px 6px; +} +.matrix__bubble { + display: inline-flex; + align-items: center; + justify-content: center; + min-width: 22px; + height: 22px; + padding: 0 6px; + font-size: 10px; + font-weight: var(--font-weight-semibold); + font-family: var(--font-family-mono); + color: var(--color-text-primary); + background: rgba(255, 255, 255, 0.85); + border: 1px solid rgba(15, 18, 22, 0.18); + border-radius: var(--radius-pill); +} +.matrix__bubble--count { + background: var(--color-text-primary); + color: var(--color-bg); + border: none; +} +[data-theme="dark"] .matrix__bubble { background: rgba(0,0,0,0.45); color: var(--color-text-primary); border-color: rgba(255,255,255,0.15); } + +.matrix__x-label { + text-align: center; + font-size: var(--font-size-sm); + font-weight: var(--font-weight-semibold); + color: var(--color-text-secondary); + letter-spacing: 0.06em; + text-transform: uppercase; + margin-top: var(--space-1); +} +.matrix__legend { + display: flex; gap: var(--space-4); flex-wrap: wrap; + font-size: var(--font-size-xs); + margin-top: var(--space-3); + color: var(--color-text-secondary); +} +.matrix__legend-swatch { + display: inline-block; width: 14px; height: 14px; + border-radius: 3px; margin-right: 6px; vertical-align: -3px; +} + +/* ============================================================================= + 3. FINDINGS-BROWSER + ============================================================================= */ +.findings { + display: grid; + grid-template-columns: 360px 1fr; + gap: var(--space-6); + align-items: start; +} +.findings__list { + background: var(--color-surface); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-lg); + overflow: hidden; + max-height: 640px; + display: flex; + flex-direction: column; +} +.findings__toolbar { + display: flex; + gap: var(--space-2); + padding: var(--space-3); + border-bottom: 1px solid var(--color-border-subtle); + background: var(--color-bg-soft); + align-items: center; +} +.findings__search { + flex: 1; + padding: 6px 10px; + font-size: var(--font-size-xs); + border: 1px solid var(--color-border-moderate); + border-radius: var(--radius-md); + background: var(--color-surface); + color: inherit; + font-family: inherit; +} +.findings__group { + border-bottom: 1px solid var(--color-border-subtle); +} +.findings__group-header { + padding: 8px 12px; + font-size: var(--font-size-xs); + text-transform: uppercase; + letter-spacing: 0.08em; + font-weight: var(--font-weight-semibold); + color: var(--color-text-secondary); + background: var(--color-bg-soft); + display: flex; + justify-content: space-between; + align-items: center; +} +.findings__items { + list-style: none; + margin: 0; + padding: 0; + overflow-y: auto; +} +.findings__item { + padding: 10px 12px; + border-top: 1px solid var(--color-border-subtle); + cursor: pointer; + display: grid; + grid-template-columns: auto 1fr; + gap: 8px 10px; + align-items: start; + transition: background var(--duration-fast) var(--ease-default); +} +.findings__item:first-child { border-top: none; } +.findings__item:hover { background: var(--color-bg-soft); } +.findings__item[aria-selected="true"] { + background: var(--color-primary-50); + box-shadow: inset 3px 0 0 var(--color-primary-500); +} +[data-theme="dark"] .findings__item[aria-selected="true"] { background: var(--color-primary-900); } +.findings__item-id { + font-family: var(--font-family-mono); + font-size: 11px; + color: var(--color-text-tertiary); + grid-column: 2; +} +.findings__item-title { + font-size: var(--font-size-sm); + font-weight: var(--font-weight-medium); + line-height: 1.4; + color: var(--color-text-primary); + grid-column: 2; +} +.findings__item-meta { + display: flex; + gap: 6px; + flex-wrap: wrap; + grid-column: 2; +} +.findings__item-severity-dot { + width: 8px; height: 8px; border-radius: 50%; + margin-top: 7px; + grid-row: 1 / span 3; +} +.findings__item-severity-dot[data-severity="critical"] { background: var(--color-severity-critical); } +.findings__item-severity-dot[data-severity="high"] { background: var(--color-severity-high); } +.findings__item-severity-dot[data-severity="medium"] { background: var(--color-severity-medium); } +.findings__item-severity-dot[data-severity="low"] { background: var(--color-severity-low); } +.findings__item-severity-dot[data-severity="info"] { background: var(--color-text-tertiary); } + +.findings__detail { + background: var(--color-surface); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-lg); + padding: var(--space-6); +} + +@media (max-width: 880px) { .findings { grid-template-columns: 1fr; } } + +/* ============================================================================= + 4. CRITIQUE-CARD + ============================================================================= */ +.critique-card { + background: var(--color-surface); + border: 1px solid var(--color-border-subtle); + border-left: 4px solid var(--color-border-moderate); + border-radius: var(--radius-md); + padding: var(--space-4) var(--space-5); + display: flex; + flex-direction: column; + gap: var(--space-3); +} +.critique-card[data-severity="critical"] { border-left-color: var(--color-severity-critical); } +.critique-card[data-severity="high"] { border-left-color: var(--color-severity-high); } +.critique-card[data-severity="medium"] { border-left-color: var(--color-severity-medium); } +.critique-card[data-severity="low"] { border-left-color: var(--color-severity-low); } +.critique-card[data-severity="info"] { border-left-color: var(--color-state-info); } + +.critique-card__header { + display: flex; + justify-content: space-between; + align-items: flex-start; + gap: var(--space-3); +} +.critique-card__title { + font-size: var(--font-size-md); + font-weight: var(--font-weight-semibold); + margin: 0; +} +.critique-card__meta { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; } +.critique-card__id { + font-family: var(--font-family-mono); + font-size: var(--font-size-xs); + color: var(--color-text-tertiary); +} +.critique-card__evidence { + font-family: var(--font-family-mono); + font-size: var(--font-size-xs); + background: var(--color-surface-sunken); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-sm); + padding: 8px 10px; + white-space: pre-wrap; + word-break: break-word; + color: var(--color-text-secondary); +} +.critique-card__recommendation { + font-size: var(--font-size-sm); + color: var(--color-text-primary); + line-height: var(--line-height-snug); +} +.critique-card__actions { + display: flex; + gap: var(--space-2); + margin-top: 4px; + flex-wrap: wrap; +} +.critique-card[data-status="approved"] { opacity: 0.65; background: var(--color-bg-soft); } +.critique-card[data-status="rejected"] { opacity: 0.5; } + +/* ============================================================================= + 5. WIZARD / STEPPER + ============================================================================= */ +.stepper { + display: flex; + gap: 0; + margin-bottom: var(--space-8); + border-bottom: 1px solid var(--color-border-subtle); + padding-bottom: var(--space-4); + overflow-x: auto; +} +.stepper__step { + flex: 1; + min-width: 140px; + display: flex; + align-items: center; + gap: var(--space-3); + padding: 0 var(--space-4) 0 0; + text-align: left; + background: none; + border: none; + cursor: pointer; + position: relative; + font-family: inherit; + color: var(--color-text-tertiary); +} +.stepper__step:not(:last-child)::after { + content: ''; + position: absolute; + right: 0; + top: 50%; + transform: translateY(-50%); + width: 16px; + height: 1px; + background: var(--color-border-moderate); +} +.stepper__step-number { + display: flex; + align-items: center; + justify-content: center; + width: 28px; height: 28px; + border-radius: 50%; + border: 1.5px solid var(--color-border-moderate); + font-size: var(--font-size-sm); + font-weight: var(--font-weight-semibold); + color: var(--color-text-tertiary); + background: var(--color-surface); + flex-shrink: 0; + font-variant-numeric: tabular-nums; +} +.stepper__step-text { + display: flex; + flex-direction: column; + gap: 1px; + min-width: 0; +} +.stepper__step-label { + font-size: var(--font-size-sm); + font-weight: var(--font-weight-medium); + color: inherit; + line-height: 1.3; +} +.stepper__step-hint { + font-size: var(--font-size-xs); + color: var(--color-text-tertiary); + line-height: 1.3; +} +.stepper__step[data-state="active"] { color: var(--color-text-primary); } +.stepper__step[data-state="active"] .stepper__step-number { border-color: var(--color-primary-500); background: var(--color-primary-500); color: #fff; } +.stepper__step[data-state="complete"] { color: var(--color-text-secondary); } +.stepper__step[data-state="complete"] .stepper__step-number { border-color: var(--color-state-success); background: var(--color-state-success); color: #fff; } +.stepper__step[data-state="complete"] .stepper__step-number::before { content: '✓'; font-size: 14px; } +.stepper__step[data-state="complete"] .stepper__step-number-text { display: none; } + +.wizard__panel { display: none; } +.wizard__panel[data-active="true"] { display: block; } +.wizard__nav { + display: flex; + justify-content: space-between; + margin-top: var(--space-8); + padding-top: var(--space-6); + border-top: 1px solid var(--color-border-subtle); +} + +/* ============================================================================= + 6. LIVE-METER + ============================================================================= */ +.live-meter { + display: grid; + gap: var(--space-3); +} +.live-meter__row { + display: grid; + grid-template-columns: 180px 1fr 56px; + gap: var(--space-3); + align-items: center; + font-size: var(--font-size-sm); +} +.live-meter__label { color: var(--color-text-secondary); } +.live-meter__bar { + height: 8px; + background: var(--color-surface-sunken); + border-radius: var(--radius-pill); + overflow: hidden; + position: relative; +} +.live-meter__bar-fill { + height: 100%; + background: var(--color-primary-500); + border-radius: var(--radius-pill); + transition: width var(--duration-normal) var(--ease-default); +} +.live-meter__bar-fill[data-state="pass"] { background: var(--color-state-success); } +.live-meter__bar-fill[data-state="weak"] { background: var(--color-severity-medium); } +.live-meter__bar-fill[data-state="fail"] { background: var(--color-severity-critical); } +.live-meter__value { + text-align: right; + font-variant-numeric: tabular-nums; + font-weight: var(--font-weight-semibold); + font-size: var(--font-size-sm); +} +.live-meter__overall { + display: flex; + justify-content: space-between; + align-items: baseline; + padding: var(--space-3) var(--space-4); + background: var(--color-bg-soft); + border-radius: var(--radius-md); + margin-top: var(--space-2); +} +.live-meter__overall-value { + font-size: var(--font-size-2xl); + font-weight: var(--font-weight-bold); + font-variant-numeric: tabular-nums; + letter-spacing: -0.02em; +} + +/* Antipattern annotations (inline, subtle) */ +.lint-annotation { + display: inline-flex; + gap: 6px; + padding: 6px 10px; + margin-top: 6px; + background: var(--color-severity-medium-soft); + border-left: 3px solid var(--color-severity-medium); + border-radius: 0 var(--radius-sm) var(--radius-sm) 0; + font-size: var(--font-size-xs); + color: var(--color-severity-medium-on); + line-height: var(--line-height-snug); +} +.lint-annotation--error { + background: var(--color-severity-critical-soft); + color: var(--color-severity-critical); + border-left-color: var(--color-severity-critical); +} +.lint-annotation__code { + font-family: var(--font-family-mono); + font-weight: var(--font-weight-semibold); +} + +/* ============================================================================= + App shell — header / nav (used by Scenario A and showcase) + ============================================================================= */ +.app-header { + position: sticky; + top: 0; + z-index: 50; + background: var(--color-surface); + border-bottom: 1px solid var(--color-border-subtle); + padding: var(--space-3) var(--space-6); + display: flex; + align-items: center; + gap: var(--space-4); +} +.app-header__brand { + display: flex; + align-items: center; + gap: var(--space-3); + font-weight: var(--font-weight-semibold); + font-size: var(--font-size-md); + text-decoration: none; + color: var(--color-text-primary); +} +.app-header__brand-mark { + width: 28px; height: 28px; + background: var(--color-primary-500); + border-radius: var(--radius-sm); + display: flex; align-items: center; justify-content: center; + color: #fff; + font-family: var(--font-family-mono); + font-size: 13px; + font-weight: 700; +} +.app-header__breadcrumb { + color: var(--color-text-tertiary); + font-size: var(--font-size-sm); + display: flex; gap: var(--space-2); align-items: center; +} +.app-header__spacer { flex: 1; } +.app-header__actions { display: flex; gap: var(--space-2); align-items: center; } + +.theme-toggle { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 6px 10px; + border: 1px solid var(--color-border-moderate); + border-radius: var(--radius-md); + background: var(--color-surface); + color: var(--color-text-secondary); + font-size: var(--font-size-xs); + font-family: inherit; + cursor: pointer; +} +.theme-toggle:hover { border-color: var(--color-border-strong); color: var(--color-text-primary); } + +/* Detail sidepanel (slides from right) */ +.sidepanel { + position: fixed; + inset: 0 0 0 auto; + width: min(560px, 92vw); + background: var(--color-surface); + border-left: 1px solid var(--color-border-subtle); + box-shadow: var(--shadow-lg); + transform: translateX(100%); + transition: transform var(--duration-normal) var(--ease-default); + z-index: 100; + display: flex; + flex-direction: column; + overflow: hidden; +} +.sidepanel[data-open="true"] { transform: translateX(0); } +.sidepanel__header { + padding: var(--space-4) var(--space-6); + border-bottom: 1px solid var(--color-border-subtle); + display: flex; justify-content: space-between; align-items: flex-start; + gap: var(--space-3); +} +.sidepanel__body { + flex: 1; + overflow-y: auto; + padding: var(--space-6); +} +.sidepanel__close { + background: none; border: none; cursor: pointer; + width: 32px; height: 32px; + border-radius: var(--radius-sm); + display: flex; align-items: center; justify-content: center; + color: var(--color-text-secondary); +} +.sidepanel__close:hover { background: var(--color-bg-soft); color: var(--color-text-primary); } + +.scrim { + position: fixed; inset: 0; + background: var(--color-overlay); + opacity: 0; + pointer-events: none; + transition: opacity var(--duration-normal) var(--ease-default); + z-index: 99; +} +.scrim[data-open="true"] { opacity: 1; pointer-events: auto; } diff --git a/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts.css b/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts.css new file mode 100644 index 0000000..3f25148 --- /dev/null +++ b/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts.css @@ -0,0 +1,84 @@ +/* Code generated by sync-design-system.mjs; DO NOT EDIT. */ +/* + * Self-hosted web fonts for Playground Design System. + * + * All three families are licensed under SIL Open Font License 1.1. + * Full license text and provenance: ./fonts/LICENSES.md + * + * Why self-hosted: + * - No external requests (no fonts.googleapis.com, no IP/UA leakage). + * - Works offline / behind air-gapped firewalls. + * - GDPR-compliant for Norwegian public-sector deployments. + * + * Bundle size: ~940 KB total across 9 woff2 files. + * Loaded via font-display: swap to avoid FOIT. + */ + +/* ========== Inter (UI / body) ========== */ +@font-face { + font-family: "Inter"; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url("./fonts/Inter-Regular.woff2") format("woff2"); +} +@font-face { + font-family: "Inter"; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url("./fonts/Inter-Medium.woff2") format("woff2"); +} +@font-face { + font-family: "Inter"; + font-style: normal; + font-weight: 600; + font-display: swap; + src: url("./fonts/Inter-SemiBold.woff2") format("woff2"); +} +@font-face { + font-family: "Inter"; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url("./fonts/Inter-Bold.woff2") format("woff2"); +} + +/* ========== JetBrains Mono (code) ========== */ +@font-face { + font-family: "JetBrains Mono"; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url("./fonts/JetBrainsMono-Regular.woff2") format("woff2"); +} +@font-face { + font-family: "JetBrains Mono"; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url("./fonts/JetBrainsMono-Medium.woff2") format("woff2"); +} +@font-face { + font-family: "JetBrains Mono"; + font-style: normal; + font-weight: 600; + font-display: swap; + src: url("./fonts/JetBrainsMono-SemiBold.woff2") format("woff2"); +} + +/* ========== Source Serif 4 (occasional editorial accents) ========== */ +@font-face { + font-family: "Source Serif 4"; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url("./fonts/SourceSerif4-Regular.woff2") format("woff2"); +} +@font-face { + font-family: "Source Serif 4"; + font-style: normal; + font-weight: 600; + font-display: swap; + src: url("./fonts/SourceSerif4-Semibold.woff2") format("woff2"); +} diff --git a/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts/Inter-Bold.woff2 b/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts/Inter-Bold.woff2 new file mode 100644 index 0000000..0f1b157 Binary files /dev/null and b/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts/Inter-Bold.woff2 differ diff --git a/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts/Inter-Medium.woff2 b/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts/Inter-Medium.woff2 new file mode 100644 index 0000000..0fd2ee7 Binary files /dev/null and b/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts/Inter-Medium.woff2 differ diff --git a/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts/Inter-Regular.woff2 b/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts/Inter-Regular.woff2 new file mode 100644 index 0000000..b8699af Binary files /dev/null and b/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts/Inter-Regular.woff2 differ diff --git a/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts/Inter-SemiBold.woff2 b/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts/Inter-SemiBold.woff2 new file mode 100644 index 0000000..95c48b1 Binary files /dev/null and b/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts/Inter-SemiBold.woff2 differ diff --git a/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts/JetBrainsMono-Medium.woff2 b/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts/JetBrainsMono-Medium.woff2 new file mode 100644 index 0000000..669d04c Binary files /dev/null and b/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts/JetBrainsMono-Medium.woff2 differ diff --git a/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts/JetBrainsMono-Regular.woff2 b/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts/JetBrainsMono-Regular.woff2 new file mode 100644 index 0000000..40da427 Binary files /dev/null and b/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts/JetBrainsMono-Regular.woff2 differ diff --git a/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts/JetBrainsMono-SemiBold.woff2 b/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts/JetBrainsMono-SemiBold.woff2 new file mode 100644 index 0000000..5ead7b0 Binary files /dev/null and b/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts/JetBrainsMono-SemiBold.woff2 differ diff --git a/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts/LICENSE-Inter.txt b/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts/LICENSE-Inter.txt new file mode 100644 index 0000000..9b2ca37 --- /dev/null +++ b/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts/LICENSE-Inter.txt @@ -0,0 +1,92 @@ +Copyright (c) 2016 The Inter Project Authors (https://github.com/rsms/inter) + +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 AND 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/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts/LICENSE-JetBrainsMono.txt b/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts/LICENSE-JetBrainsMono.txt new file mode 100644 index 0000000..8bee414 --- /dev/null +++ b/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts/LICENSE-JetBrainsMono.txt @@ -0,0 +1,93 @@ +Copyright 2020 The JetBrains Mono Project Authors (https://github.com/JetBrains/JetBrainsMono) + +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: +https://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/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts/LICENSE-SourceSerif4.md b/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts/LICENSE-SourceSerif4.md new file mode 100644 index 0000000..ebe298c --- /dev/null +++ b/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts/LICENSE-SourceSerif4.md @@ -0,0 +1,93 @@ +Copyright 2014 - 2023 Adobe (http://www.adobe.com/), with Reserved Font Name ‘Source’. All Rights Reserved. Source is a trademark of Adobe in the United States and/or other countries. + +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/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts/LICENSES.md b/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts/LICENSES.md new file mode 100644 index 0000000..0389aa8 --- /dev/null +++ b/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts/LICENSES.md @@ -0,0 +1,42 @@ +# Font Licenses + +All three font families bundled with Playground Design System are licensed +under the SIL Open Font License, Version 1.1 (OFL-1.1). They are free to +use, modify, embed, and redistribute under the terms of OFL-1.1. + +Full license text per family: + +- **Inter** (Regular, Medium, SemiBold, Bold) — `LICENSE-Inter.txt` + Copyright (c) 2016 The Inter Project Authors + Source: https://github.com/rsms/inter + Version bundled: 4.0 + +- **JetBrains Mono** (Regular, Medium, SemiBold) — `LICENSE-JetBrainsMono.txt` + Copyright 2020 The JetBrains Mono Project Authors + Source: https://github.com/JetBrains/JetBrainsMono + Version bundled: 2.304 + +- **Source Serif 4** (Regular, Semibold) — `LICENSE-SourceSerif4.md` + Copyright 2014–2023 Adobe (Reserved Font Name "Source") + Source: https://github.com/adobe-fonts/source-serif + Version bundled: 4.005 + +## Provenance + +Files in this directory were obtained from the upstream release artifacts +linked above on 2026-05-03. Source Serif 4 woff2 files were generated locally +from the desktop OTF release using `fonttools ttLib.woff2 compress`; all +others are unmodified from upstream webfont releases. + +## Why bundled + +These fonts ship with the design system to eliminate runtime requests to +external CDNs (e.g., fonts.googleapis.com). This guarantees: + +- No data leakage about end-user IPs / User-Agents to third parties. +- GDPR compliance for Norwegian public-sector deployments. +- Functioning Playgrounds in offline / air-gapped environments. + +Each Playground HTML loads `../shared/playground-design-system/fonts.css`, +which declares all `@font-face` rules pointing at the .woff2 files in this +directory. diff --git a/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts/SourceSerif4-Regular.woff2 b/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts/SourceSerif4-Regular.woff2 new file mode 100644 index 0000000..5858db3 Binary files /dev/null and b/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts/SourceSerif4-Regular.woff2 differ diff --git a/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts/SourceSerif4-Semibold.woff2 b/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts/SourceSerif4-Semibold.woff2 new file mode 100644 index 0000000..3bb9b6c Binary files /dev/null and b/plugins/ms-ai-architect/playground/vendor/playground-design-system/fonts/SourceSerif4-Semibold.woff2 differ diff --git a/plugins/ms-ai-architect/playground/vendor/playground-design-system/print.css b/plugins/ms-ai-architect/playground/vendor/playground-design-system/print.css new file mode 100644 index 0000000..77a0a09 --- /dev/null +++ b/plugins/ms-ai-architect/playground/vendor/playground-design-system/print.css @@ -0,0 +1,176 @@ +/* Code generated by sync-design-system.mjs; DO NOT EDIT. */ +/* ============================================================================= + print.css — A4 print stylesheet for offentlige dokumenter + - Severity-mønstre (skravur) som fungerer i B/W + - Header/footer med kommune-logo-slot, signaturfelt, paginering + - 12pt minimum kropp, 11pt for metadata + - Skjuler interaktiv chrome (header, knapper, toggles) + ============================================================================= */ + +@page { + size: A4 portrait; + margin: 22mm 18mm 24mm 18mm; + @bottom-right { content: counter(page) " / " counter(pages); font-family: "Inter", sans-serif; font-size: 9pt; color: #555; } +} +@page :first { @top-left { content: none; } } +@page landscape { size: A4 landscape; } + +/* SVG severity-mønstre (skravur) — definert i print-only inline-svg. + For å bruke: legg til class .pattern-low/.pattern-medium/etc. på elementet + som ellers fyller med severity-fargen. */ +@media print { + + :root { + --color-bg: #FFFFFF; + --color-surface: #FFFFFF; + --color-surface-sunken: #F5F5F5; + --color-bg-soft: #F7F7F7; + --color-border-subtle: #C7C7C7; + --color-border-moderate: #888888; + --color-text-primary: #000000; + --color-text-secondary: #2A2A2A; + --color-text-tertiary: #555555; + } + + html, body { background: #FFFFFF !important; color: #000 !important; font-size: 11pt !important; } + body { -webkit-print-color-adjust: exact; print-color-adjust: exact; } + + /* Hide interactive chrome */ + .app-header, header.app-header, + .theme-toggle, #theme-toggle, #themeToggle, + .filter-bar, .view-toggle, .screen-tabs, + .btn--primary, .btn--secondary, .btn--ghost, + .live-dot, .pane__head .badge, + .accept-banner button, + .scenario-card .btn, + .footer { display: none !important; } + + /* Container = full width on print */ + .container, .container--wide { max-width: none !important; padding: 0 !important; } + + /* Body type */ + body, p, li, dd, dt, td, th, .field__value { + font-family: "Inter", sans-serif; + font-size: 11pt; line-height: 1.45; color: #000; + } + h1 { font-size: 22pt; line-height: 1.2; margin: 0 0 6pt; } + h2 { font-size: 16pt; line-height: 1.25; margin: 18pt 0 6pt; page-break-after: avoid; } + h3 { font-size: 13pt; margin: 12pt 0 4pt; page-break-after: avoid; } + h4 { font-size: 11pt; margin: 10pt 0 3pt; } + + /* Page breaks */ + .page-break { page-break-before: always; } + .avoid-break, .finding, .critique, .scenario-card, table, figure { + page-break-inside: avoid; + } + + /* Severity patterns (B/W-safe). Stack pattern-bg + dotted/diag border indicators. */ + .matrix__cell[data-score], + .badge--severity-low, .badge--severity-medium, .badge--severity-high, + .badge--severity-critical, .badge--severity-extreme { + background-color: #FFF !important; + color: #000 !important; + border: 1px solid #000 !important; + } + .badge--severity-low::before, .badge--severity-medium::before, + .badge--severity-high::before, .badge--severity-critical::before, + .badge--severity-extreme::before { + content: ""; display: inline-block; + width: 7pt; height: 7pt; margin-right: 4pt; + border: 1px solid #000; + vertical-align: middle; + } + .badge--severity-low::before { background: #FFF; } + .badge--severity-medium::before { background: repeating-linear-gradient(45deg, #000 0 0.6pt, transparent 0.6pt 3pt); } + .badge--severity-high::before { background: repeating-linear-gradient(45deg, #000 0 1pt, transparent 1pt 2.5pt); } + .badge--severity-critical::before { background: repeating-linear-gradient(0deg, #000 0 0.5pt, transparent 0.5pt 2pt), + repeating-linear-gradient(90deg, #000 0 0.5pt, transparent 0.5pt 2pt); } + .badge--severity-extreme::before { background: #000; } + + /* Matrix cells in print: skravur i stedet for farge */ + .matrix__cell { color: #000 !important; border: 0.5pt solid #888 !important; } + .matrix__cell[data-score]:not([data-score="0"]) { background: #FFF !important; } + .matrix__cell[data-score="1"], .matrix__cell[data-score="2"], + .matrix__cell[data-score="3"], .matrix__cell[data-score="4"] { + background: #FFF !important; + } + .matrix__cell[data-score="5"], .matrix__cell[data-score="6"], .matrix__cell[data-score="8"] { + background: repeating-linear-gradient(45deg, rgba(0,0,0,0.18) 0 0.5pt, transparent 0.5pt 4pt) !important; + } + .matrix__cell[data-score="9"], .matrix__cell[data-score="10"], .matrix__cell[data-score="12"] { + background: repeating-linear-gradient(45deg, rgba(0,0,0,0.32) 0 0.7pt, transparent 0.7pt 3pt) !important; + } + .matrix__cell[data-score="15"], .matrix__cell[data-score="16"], .matrix__cell[data-score="20"] { + background: repeating-linear-gradient(45deg, rgba(0,0,0,0.48) 0 1pt, transparent 1pt 2pt) !important; + } + .matrix__cell[data-score="25"] { background: #000 !important; color: #FFF !important; } + .matrix__cell[data-score="25"] .matrix__cell-score { color: #FFF !important; } + + /* Surfaces flat */ + .card, .pane, .finding, .critique, .scenario-card, .posture-summary, .verdict-block { + background: #FFF !important; + border: 0.5pt solid #888 !important; + box-shadow: none !important; + border-radius: 0 !important; + } + + /* Links visible but not underlined-everything */ + a { color: #000; text-decoration: none; } + a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 9pt; color: #555; } + a[href^="#"]::after, a[href^="/"]::after, a:not([href*="://"])::after { content: ""; } + + /* Standard footer block: signaturfelt for offentlige dokumenter */ + .print-footer { + margin-top: 24pt; + padding-top: 10pt; + border-top: 0.5pt solid #888; + display: grid; + grid-template-columns: 1fr 1fr; + gap: 18pt; + font-size: 10pt; + } + .print-signature { display: flex; flex-direction: column; gap: 28pt; } + .print-signature__line { + border-bottom: 0.5pt solid #000; + height: 28pt; + } + .print-signature__caption { + font-size: 9pt; + color: #555; + } + + /* Header for offisielle rapporter — kommune-logo-slot */ + .print-header { + display: grid; + grid-template-columns: auto 1fr; + gap: 14pt; + align-items: center; + padding-bottom: 10pt; + margin-bottom: 16pt; + border-bottom: 0.5pt solid #888; + } + .print-header__logo { + width: 40pt; height: 40pt; + border: 0.5pt solid #888; + display: flex; align-items: center; justify-content: center; + font-family: "Inter", sans-serif; font-size: 9pt; color: #888; + } + .print-header__meta { font-size: 9pt; color: #555; } + .print-header__meta strong { color: #000; } + + /* Avoid orphan headings */ + h2, h3, h4 { orphans: 3; widows: 3; } + p, li { orphans: 2; widows: 2; } +} + +/* Screen-mode preview class — see print preview without actually printing */ +.preview-print { background: #ddd; padding: var(--space-8); } +.preview-print .a4 { + width: 210mm; min-height: 297mm; + margin: 0 auto; + background: #fff; + padding: 22mm 18mm; + box-shadow: 0 6px 24px rgba(0,0,0,0.18); + font-size: 11pt; line-height: 1.45; color: #000; +} +.preview-print .a4 + .a4 { margin-top: 12mm; } diff --git a/plugins/ms-ai-architect/playground/vendor/playground-design-system/schemas/finding.schema.json b/plugins/ms-ai-architect/playground/vendor/playground-design-system/schemas/finding.schema.json new file mode 100644 index 0000000..74605e2 --- /dev/null +++ b/plugins/ms-ai-architect/playground/vendor/playground-design-system/schemas/finding.schema.json @@ -0,0 +1,88 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://playground-ds.no/schemas/finding.json", + "title": "Finding", + "description": "Et enkelt funn fra en plugin-skanning. Brukes av llm-security, config-audit, ultraplan-review og ms-ai-review.", + "type": "object", + "required": ["id", "title", "severity", "source"], + "properties": { + "id": { + "type": "string", + "description": "Stabil ID, f.eks. DDT-2026-118-F-001", + "pattern": "^[A-Z0-9-]{4,}$" + }, + "title": { "type": "string", "minLength": 4, "maxLength": 140 }, + "severity": { + "enum": ["info", "low", "medium", "high", "critical"], + "description": "Standard 5-trinns skala. Maps til CSS-tokens --color-severity-*." + }, + "score": { + "type": "number", "minimum": 0, "maximum": 10, + "description": "CVSS-lignende numerisk score. Valgfri — severity er primær." + }, + "rules": { + "type": "array", + "items": { "type": "string", "pattern": "^[A-Z]{2,4}[0-9]{2}(\\.[0-9]+)?$" }, + "description": "Regler/categories truffet, f.eks. LLM01, ASI02, DDT01" + }, + "source": { + "type": "object", + "required": ["kind", "ref"], + "properties": { + "kind": { "enum": ["document", "prompt-response", "code-file", "config-file", "okr-set"] }, + "ref": { "type": "string", "description": "Filnavn / URL / sak-ID" }, + "line": { "type": "integer", "minimum": 1 }, + "col": { "type": "integer", "minimum": 0 }, + "snippet": { "type": "string", "maxLength": 800 } + } + }, + "evidence": { + "type": "array", + "items": { + "type": "object", + "required": ["kind", "value"], + "properties": { + "kind": { "enum": ["text", "codepoint", "metric", "url", "image"] }, + "value": { "type": "string" }, + "label": { "type": "string" } + } + } + }, + "rationale": { "type": "string", "description": "Norsk forklaring av hvorfor dette er et problem i denne konteksten" }, + "recommendation": { + "type": "object", + "properties": { + "summary": { "type": "string" }, + "steps": { "type": "array", "items": { "type": "string" } }, + "ttf": { "type": "string", "description": "Tid til løsning, f.eks. '2 t', '1 d', '5 d'" }, + "owner": { "type": "string", "description": "Foreslått eier (rolle eller person)" } + } + }, + "references": { + "type": "array", + "items": { + "type": "object", + "properties": { + "label": { "type": "string" }, + "url": { "type": "string", "format": "uri" } + } + } + }, + "status": { + "enum": ["new", "acknowledged", "in-progress", "fixed", "accepted-risk", "false-positive"], + "default": "new" + }, + "acceptance": { + "type": "object", + "description": "Påkrevd hvis status = accepted-risk og severity ≥ high", + "properties": { + "approver": { "type": "string" }, + "date": { "type": "string", "format": "date" }, + "rationale": { "type": "string" }, + "review_by": { "type": "string", "format": "date" } + } + }, + "created": { "type": "string", "format": "date-time" }, + "updated": { "type": "string", "format": "date-time" } + } +} diff --git a/plugins/ms-ai-architect/playground/vendor/playground-design-system/schemas/okr-set.schema.json b/plugins/ms-ai-architect/playground/vendor/playground-design-system/schemas/okr-set.schema.json new file mode 100644 index 0000000..0af4597 --- /dev/null +++ b/plugins/ms-ai-architect/playground/vendor/playground-design-system/schemas/okr-set.schema.json @@ -0,0 +1,78 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://playground-ds.no/schemas/okr-set.json", + "title": "OKR-sett", + "description": "Et OKR-sett: ett mål (Objective) med 1–6 nøkkelresultater (KR). Brukes av OKR live-writer.", + "type": "object", + "required": ["id", "objective", "key_results", "owner", "period"], + "properties": { + "id": { "type": "string" }, + "owner": { + "type": "object", + "required": ["name", "unit"], + "properties": { + "name": { "type": "string" }, + "unit": { "type": "string", "description": "Avdeling/seksjon" }, + "org": { "type": "string", "description": "Kommune/etat" } + } + }, + "period": { + "type": "object", + "required": ["kind", "label", "start", "end"], + "properties": { + "kind": { "enum": ["tertial", "kvartal", "halvår", "år"] }, + "label": { "type": "string", "description": "f.eks. 'T2 2026'" }, + "start": { "type": "string", "format": "date" }, + "end": { "type": "string", "format": "date" } + } + }, + "objective": { + "type": "object", + "required": ["text"], + "properties": { + "text": { "type": "string", "minLength": 10, "maxLength": 240 }, + "rationale": { "type": "string" } + } + }, + "key_results": { + "type": "array", "minItems": 1, "maxItems": 6, + "items": { + "type": "object", + "required": ["id", "text"], + "properties": { + "id": { "type": "string", "pattern": "^KR[0-9]+$" }, + "text": { "type": "string" }, + "metric": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "unit": { "type": "string", "description": "%, dager, kr, antall, …" }, + "baseline": { "type": "number" }, + "target": { "type": "number" }, + "stretch": { "type": "number" }, + "source": { "type": "string", "description": "KPI-katalog ref / Tableau-sett / etc." } + } + }, + "deadline": { "type": "string", "format": "date" } + } + } + }, + "score": { + "type": "object", + "description": "Generert av OKR-writer ved kvalitetsanalyse", + "properties": { + "overall": { "type": "number", "minimum": 0, "maximum": 100 }, + "measurability": { "type": "number" }, + "specificity": { "type": "number" }, + "ambition": { "type": "number" }, + "actionability": { "type": "number" } + } + }, + "critiques": { + "type": "array", + "items": { "$ref": "https://playground-ds.no/schemas/finding.json" } + }, + "version": { "type": "string", "description": "Semver eller utkast 0.4-stil" }, + "status": { "enum": ["draft", "in-review", "approved", "active", "closed"], "default": "draft" } + } +} diff --git a/plugins/ms-ai-architect/playground/vendor/playground-design-system/schemas/ros-threat.schema.json b/plugins/ms-ai-architect/playground/vendor/playground-design-system/schemas/ros-threat.schema.json new file mode 100644 index 0000000..8b55c80 --- /dev/null +++ b/plugins/ms-ai-architect/playground/vendor/playground-design-system/schemas/ros-threat.schema.json @@ -0,0 +1,59 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://playground-ds.no/schemas/ros-threat.json", + "title": "ROS-trussel", + "description": "Én identifisert trussel i en risiko- og sårbarhetsanalyse. NS 5814-justert.", + "type": "object", + "required": ["id", "title", "category", "inherent"], + "properties": { + "id": { "type": "string", "pattern": "^T-[0-9]{3,}$" }, + "title": { "type": "string" }, + "description": { "type": "string" }, + "category": { + "enum": ["personvern", "informasjonssikkerhet", "datakvalitet", + "compliance", "dataintegritet", "leverandørrisiko", + "tilgjengelighet", "omdømme", "økonomi", "andre"] + }, + "actors": { + "type": "array", + "items": { "enum": ["intern-bruker", "saksbehandler", "innbygger", "ekstern-aktør", "leverandør", "system", "ai-modell"] } + }, + "inherent": { + "type": "object", + "required": ["likelihood", "consequence"], + "properties": { + "likelihood": { "type": "integer", "minimum": 1, "maximum": 5 }, + "consequence": { "type": "integer", "minimum": 1, "maximum": 5 }, + "rationale": { "type": "string" } + } + }, + "controls": { + "type": "array", + "items": { + "type": "object", + "required": ["id", "title"], + "properties": { + "id": { "type": "string", "pattern": "^M-[0-9]{3,}$" }, + "title": { "type": "string" }, + "kind": { "enum": ["preventiv", "deteksjon", "korreksjon", "policy", "opplæring", "teknisk"] }, + "status": { "enum": ["planlagt", "implementert", "validert", "ute-av-drift"] }, + "owner": { "type": "string" }, + "due": { "type": "string", "format": "date" } + } + } + }, + "residual": { + "type": "object", + "properties": { + "likelihood": { "type": "integer", "minimum": 1, "maximum": 5 }, + "consequence": { "type": "integer", "minimum": 1, "maximum": 5 }, + "rationale": { "type": "string" } + } + }, + "regulatory_refs": { + "type": "array", + "items": { "type": "string", "description": "GDPR Art. 35, AI Act Art. 6, NS 5814, …" } + }, + "status": { "enum": ["open", "mitigating", "monitored", "closed", "transferred"], "default": "open" } + } +} diff --git a/plugins/ms-ai-architect/playground/vendor/playground-design-system/tokens.css b/plugins/ms-ai-architect/playground/vendor/playground-design-system/tokens.css new file mode 100644 index 0000000..a398cdc --- /dev/null +++ b/plugins/ms-ai-architect/playground/vendor/playground-design-system/tokens.css @@ -0,0 +1,186 @@ +/* Code generated by sync-design-system.mjs; DO NOT EDIT. */ +/* ============================================================================= + Playground Design System — tokens.css + v0.1 — Phase 1 + Aksel/Digdir-aligned. Norwegian public sector. WCAG 2.1 AA. + ============================================================================= */ + +:root { + /* ---------- Typography -------------------------------------------------- */ + --font-family-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; + --font-family-mono: "JetBrains Mono", "SF Mono", "Fira Code", ui-monospace, monospace; + --font-family-serif: "Source Serif 4", Georgia, serif; + + --font-size-xs: 13px; + --font-size-sm: 15px; + --font-size-md: 17px; /* body default */ + --font-size-lg: 19px; + --font-size-xl: 23px; + --font-size-2xl: 28px; + --font-size-3xl: 34px; + --font-size-4xl: 44px; + + --line-height-tight: 1.2; + --line-height-snug: 1.4; + --line-height-normal: 1.55; + --measure: 65ch; + + --font-weight-regular: 400; + --font-weight-medium: 500; + --font-weight-semibold: 600; + --font-weight-bold: 700; + + /* ---------- Primary (Digdir) ------------------------------------------- */ + --color-primary-50: #E8F1FB; + --color-primary-100: #C6DCF4; + --color-primary-200: #9CC0EA; + --color-primary-300: #6FA5DD; + --color-primary-400: #3B83CB; + --color-primary-500: #0062BA; /* Digdir blue */ + --color-primary-600: #00569F; + --color-primary-700: #004A8F; + --color-primary-800: #003A70; + --color-primary-900: #002F5C; + + /* ---------- Severity ramp (deuteranopia-safe) ------------------------- */ + --color-severity-low: #1A7F37; + --color-severity-medium: #BF8700; + --color-severity-high: #CC5A00; + --color-severity-critical: #A40E26; + --color-severity-extreme: #66050F; + + /* Soft fills (matrix cells, badges) */ + --color-severity-low-soft: #DDF4E4; + --color-severity-medium-soft: #FBF0CC; + --color-severity-high-soft: #FCE0CC; + --color-severity-critical-soft: #F8D7DC; + --color-severity-extreme-soft: #E8C7CC; + + /* Foreground on severity bg */ + --color-severity-low-on: #0E4A20; + --color-severity-medium-on: #5C3F00; + --color-severity-high-on: #5C2900; + --color-severity-critical-on: #FFFFFF; + --color-severity-extreme-on: #FFFFFF; + + /* ---------- State (distinct from severity) --------------------------- */ + --color-state-success: #1A7F37; + --color-state-warning: #BF8700; + --color-state-failed: #7D1A1A; /* dark desaturated red — "broke" */ + --color-state-blocked: #5C2D91; /* purple — distinct */ + --color-state-info: #0969DA; + --color-state-running: #BF8700; + --color-state-queued: #6E7781; + --color-state-pending: #4D7DAD; + --color-state-done: #1A7F37; + + /* ---------- Surface / background ------------------------------------- */ + --color-bg: #FBFAF7; /* warm off-white page */ + --color-bg-soft: #F4F2EC; /* subtle section */ + --color-surface: #FFFFFF; + --color-surface-raised: #FFFFFF; + --color-surface-sunken: #F1EEE7; + --color-overlay: rgba(15, 18, 22, 0.45); + + /* ---------- Border --------------------------------------------------- */ + --color-border-subtle: #E4E0D6; + --color-border-moderate: #C8C2B3; + --color-border-strong: #6E7781; + --color-border-focus: #0062BA; + + /* ---------- Text ----------------------------------------------------- */ + --color-text-primary: #1F2328; + --color-text-secondary: #4D5663; + --color-text-tertiary: #6E7781; + --color-text-on-primary: #FFFFFF; + --color-text-link: #00569F; + --color-text-link-hover: #002F5C; + + /* ---------- Plugin scope colors -------------------------------------- */ + --color-scope-architect: #0F6E76; /* ms-ai-architect — petrol */ + --color-scope-okr: #9A6700; /* OKR — amber */ + --color-scope-security: #A40E26; /* llm-security — crimson */ + --color-scope-ultraplan: #4338CA; /* ultraplan-local — indigo */ + --color-scope-config: #3F5963; /* config-audit — slate */ + + /* ---------- Spacing -------------------------------------------------- */ + --space-1: 4px; + --space-2: 8px; + --space-3: 12px; + --space-4: 16px; + --space-5: 20px; + --space-6: 24px; + --space-8: 32px; + --space-10: 40px; + --space-12: 48px; + --space-16: 64px; + --space-20: 80px; + + /* ---------- Radius --------------------------------------------------- */ + --radius-sm: 3px; + --radius-md: 5px; + --radius-lg: 8px; + --radius-pill: 999px; + + /* ---------- Shadow --------------------------------------------------- */ + --shadow-sm: 0 1px 2px rgba(15, 18, 22, 0.04), 0 0 0 1px rgba(15, 18, 22, 0.04); + --shadow-md: 0 2px 4px rgba(15, 18, 22, 0.06), 0 4px 12px rgba(15, 18, 22, 0.04); + --shadow-lg: 0 4px 8px rgba(15, 18, 22, 0.06), 0 12px 32px rgba(15, 18, 22, 0.06); + --shadow-focus: 0 0 0 3px rgba(0, 98, 186, 0.35); + + /* ---------- Motion --------------------------------------------------- */ + --duration-instant: 100ms; + --duration-fast: 150ms; + --duration-normal: 250ms; + --duration-slow: 400ms; + --ease-default: cubic-bezier(0.2, 0, 0, 1); + + /* ---------- Layout --------------------------------------------------- */ + --container-narrow: 720px; + --container-default: 1080px; + --container-wide: 1280px; + --sidebar-width: 280px; +} + +[data-theme="dark"] { + --color-bg: #0F1419; + --color-bg-soft: #161B22; + --color-surface: #1A2027; + --color-surface-raised: #232A33; + --color-surface-sunken: #0B1015; + + --color-border-subtle: #2A323C; + --color-border-moderate: #3B4452; + --color-border-strong: #6E7781; + + --color-text-primary: #E6EDF3; + --color-text-secondary: #B0BAC4; + --color-text-tertiary: #8B96A2; + --color-text-link: #6FA5DD; + --color-text-link-hover: #9CC0EA; + + /* Severity soft fills tuned for dark surfaces */ + --color-severity-low-soft: #163322; + --color-severity-medium-soft: #3A2C0A; + --color-severity-high-soft: #3D260F; + --color-severity-critical-soft: #3B0F18; + --color-severity-extreme-soft: #2A0408; + + --color-severity-low-on: #7FE0A0; + --color-severity-medium-on: #F2C66B; + --color-severity-high-on: #F09060; + --color-severity-critical-on: #FFFFFF; + --color-severity-extreme-on: #FFFFFF; + + --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(255, 255, 255, 0.04); + --shadow-md: 0 2px 4px rgba(0, 0, 0, 0.4), 0 4px 12px rgba(0, 0, 0, 0.3); + --shadow-lg: 0 4px 8px rgba(0, 0, 0, 0.5), 0 12px 32px rgba(0, 0, 0, 0.4); + --shadow-focus: 0 0 0 3px rgba(111, 165, 221, 0.45); +} + +/* Auto dark when no override */ +@media (prefers-color-scheme: dark) { + :root:not([data-theme]) { + color-scheme: dark; + } +}