feat(shared): add Tier 3 components (8 critical for ms-ai-architect Playground v3)

Authored in Claude Code following the design-DNA established by claude.ai/design
in v0.1 (tokens + Tier 1 + Tier 2). Visual coherence verified against existing
components via tier3-preview.html showcase.

shared/playground-design-system/components-tier3.css (~480 lines):
- pair-before-after: ROS/DPIA/AI Act inherent->residual primitive with delta
  pill (improved/worsened); responsive collapse to vertical on narrow viewports
- aiact-timeline: 4 EU AI Act milestones (2025-02-02 .. 2027-08-02) with
  per-system countdown chips (urgent/soon/distant), today-marker, and per-
  milestone passed/active/upcoming states
- tracks: Guide/Explore/Expert 3-track entry pattern carried from Playground v2,
  top-bar color coding per track
- rights-matrix: FRIA 12 EU Charter rights x 5 impact levels (Art. 27 EU AI Act)
- capability-matrix: license x kapabilitet with explicit icons per status
  (available/cost/conditional/missing) - never color-only
- agent-grid + agent-card: parallel-worker status with state pills, progress
  bars, metric chips, pulsing dot for running, distinct failure-red token
- error-summary: Aksel/GOV.UK pattern, white bg + red border + dark body text
  + red heading (NOT large pink fill — fixes contrast bug)
- guide-panel: Aksel friendly inline guidance, info/success/warn variants

Also fixes shared/playground-design-system/base.css inline-message--error which
had the same contrast bug as ErrorSummary v1: white text on light-pink soft-fill
was unreadable. Now uses surface bg + critical border + primary text + critical
strong/heading color. Same dark-mode treatment.

shared/playground-examples/tier3-preview.html (~470 lines): live demo for all
8 components with realistic Norwegian mock-data (Lier kommune ROS T-001
threat, AI Act timeline 2026-05-02 today-marker, FRIA EU Charter rights, M365
capability-matrix, 4-worker utredning grid). Used to validate visual coherence
before committing.

Updates shared/playground-design-system/README.md with Tier 3 component table
and provenance note distinguishing v0.1 (claude.ai/design) from this addition
(Claude Code).

Remaining for v0.2: 12 plugin-specific Tier 3 components (sankey/toxic-flow,
fleet-overview, kanban Keep/Review/Remove, maturity-ladder, classify-and-
transform, cycle-ribbon, persistent-antipattern badge, suppressed-signals,
ExpansionCard, ReadMore, FormProgress, Aspirational vs Committed visual). To
be generated by claude.ai/design in a supplement session before plugin
Playground work begins.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-05-02 07:22:44 +02:00
commit 992d6b3f76
4 changed files with 1237 additions and 2 deletions

View file

@ -20,6 +20,7 @@ shared/
│ ├── 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: pair-before-after, AI Act timeline, 3-track entry, FRIA rights-matrix, capability-matrix, parallel-agent-status, ErrorSummary, GuidePanel
│ ├── 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
@ -108,6 +109,21 @@ See `tokens.css` for full reference. Highlights:
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 |

View file

@ -170,9 +170,12 @@ button { font-family: inherit; }
.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-severity-critical-soft); color: var(--color-severity-critical-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--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 {

View file

@ -0,0 +1,716 @@
/* =============================================================================
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; }
}

View file

@ -0,0 +1,500 @@
<!doctype html>
<html lang="nb" data-theme="light">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Tier 3 preview — Playground Design System</title>
<link rel="stylesheet" href="../playground-design-system/tokens.css">
<link rel="stylesheet" href="../playground-design-system/base.css">
<link rel="stylesheet" href="../playground-design-system/components.css">
<link rel="stylesheet" href="../playground-design-system/components-tier2.css">
<link rel="stylesheet" href="../playground-design-system/components-tier3.css">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
.preview-section {
padding: var(--space-10) 0;
border-bottom: 1px solid var(--color-border-subtle);
}
.preview-section:last-child { border-bottom: none; }
.preview-section__heading {
display: flex;
align-items: baseline;
gap: var(--space-3);
margin-bottom: var(--space-2);
}
.preview-section__num {
font-family: var(--font-family-mono);
font-size: var(--font-size-sm);
color: var(--color-text-tertiary);
font-weight: var(--font-weight-semibold);
min-width: 32px;
}
.preview-section__intro {
max-width: 60ch;
color: var(--color-text-secondary);
margin-bottom: var(--space-6);
}
.preview-section__demo {
padding: var(--space-6);
background: var(--color-surface);
border: 1px solid var(--color-border-subtle);
border-radius: var(--radius-lg);
}
</style>
</head>
<body>
<header class="app-header">
<a class="app-header__brand" href="index.html">
<span class="app-header__brand-mark">PG</span>
Playground Design System
</a>
<span class="app-header__breadcrumb">/ Tier 3 preview</span>
<div class="app-header__spacer"></div>
<button class="theme-toggle" id="themeToggle" type="button">Mørk modus</button>
<a href="index.html" class="btn btn--ghost btn--sm">← Til oversikt</a>
</header>
<main class="container container--wide">
<div style="padding: var(--space-8) 0 var(--space-4);">
<h1>Tier 3 — Critical components</h1>
<p class="text-secondary" style="max-width: 65ch; margin-top: var(--space-3);">
8 komponenter bygd direkte for ms-ai-architect Playground v3. Hvis disse ser ut som de hører hjemme i samme familie som Tier 1 + 2, beholder vi dem og lar claude.ai/design lage de resterende 12 (sankey/toxic-flow, fleet-overview, kanban Keep/Review/Remove, maturity-ladder, classify-and-transform, cycle-ribbon, persistent-antipattern badge, suppressed-signals panel, ExpansionCard, ReadMore, FormProgress, Aspirational vs Committed visual).
</p>
</div>
<!-- 19. Pair before/after -->
<section class="preview-section">
<div class="preview-section__heading">
<span class="preview-section__num">19</span>
<h2>Inherent + residual pair</h2>
</div>
<p class="preview-section__intro">Brukes i ROS før/etter mitigering, DPIA inherent → residual, OKR check-in score over tid.</p>
<div class="preview-section__demo">
<h4 style="margin-bottom: var(--space-2);">T-001: Eksponering av personopplysninger via Copilot Chat</h4>
<div class="pair-before-after">
<div class="pair-before-after__cell pair-before-after__cell--severity-critical">
<span class="pair-before-after__cell-label">Inherent risiko</span>
<span class="pair-before-after__cell-value">20</span>
<span class="pair-before-after__cell-meta">S4 × K5 — Kritisk sone</span>
</div>
<div class="pair-before-after__arrow" aria-label="reduseres til"></div>
<div class="pair-before-after__cell pair-before-after__cell--severity-medium">
<span class="pair-before-after__cell-label">Etter M-001 + M-002</span>
<span class="pair-before-after__cell-value">8</span>
<span class="pair-before-after__cell-meta">S2 × K4 — Gul sone</span>
<span class="pair-before-after__delta pair-before-after__delta--improved">12 (60 % reduksjon)</span>
</div>
</div>
</div>
</section>
<!-- 20. AI Act timeline -->
<section class="preview-section">
<div class="preview-section__heading">
<span class="preview-section__num">20</span>
<h2>AI Act compliance-tidslinje</h2>
</div>
<p class="preview-section__intro">4 milepeler i EU AI Act med per-system countdown. Brukes i ms-ai-architect classify-flow og dashboard.</p>
<div class="preview-section__demo">
<div class="aiact-timeline">
<div class="aiact-timeline__track">
<div class="aiact-timeline__progress" style="width: 41%;"></div>
<div class="aiact-timeline__milestone" style="left: 0%;" data-state="passed">
<div class="aiact-timeline__dot"></div>
<div class="aiact-timeline__label">
<span class="aiact-timeline__label-date">2025-02-02</span>
<span class="aiact-timeline__label-name">Forbudte praksiser (Art. 5)</span>
</div>
</div>
<div class="aiact-timeline__milestone" style="left: 22%;" data-state="passed">
<div class="aiact-timeline__dot"></div>
<div class="aiact-timeline__label">
<span class="aiact-timeline__label-date">2025-08-02</span>
<span class="aiact-timeline__label-name">Governance og sanksjoner (Art. 99)</span>
</div>
</div>
<div class="aiact-timeline__today" style="left: 41%;"></div>
<div class="aiact-timeline__milestone" style="left: 60%;" data-state="active">
<div class="aiact-timeline__dot"></div>
<div class="aiact-timeline__label">
<span class="aiact-timeline__label-date">2026-08-02</span>
<span class="aiact-timeline__label-name">GPAI + Annex III høyrisiko</span>
</div>
</div>
<div class="aiact-timeline__milestone" style="left: 100%;" data-state="upcoming">
<div class="aiact-timeline__dot"></div>
<div class="aiact-timeline__label">
<span class="aiact-timeline__label-date">2027-08-02</span>
<span class="aiact-timeline__label-name">Full compliance for all høyrisiko</span>
</div>
</div>
</div>
</div>
<div style="display: flex; gap: var(--space-3); flex-wrap: wrap; margin-top: var(--space-12);">
<span class="aiact-countdown" data-urgency="urgent">
<span>Kommunal Copilot-utrulling:</span>
<span class="aiact-countdown__days">92 dager</span>
<span>til Annex III-frist</span>
</span>
<span class="aiact-countdown" data-urgency="soon">
<span>Saksbehandling AI:</span>
<span class="aiact-countdown__days">457 dager</span>
<span>til full compliance</span>
</span>
<span class="aiact-countdown" data-urgency="distant">
<span>Intern HR-bot:</span>
<span class="aiact-countdown__days">457 dager</span>
<span>(begrenset risiko)</span>
</span>
</div>
</div>
</section>
<!-- 21. 3-track entry -->
<section class="preview-section">
<div class="preview-section__heading">
<span class="preview-section__num">21</span>
<h2>3-track entry</h2>
</div>
<p class="preview-section__intro">Carry-forward fra Playground v2. Den første beslutningen — bruker velger sin ferdighetsnivå-vei inn i Playground.</p>
<div class="preview-section__demo">
<div class="tracks">
<a class="tracks__card tracks__card--guided" href="#">
<div class="tracks__card-icon">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2v8M12 22v-2M4.93 4.93l5.66 5.66M19.07 19.07l-1.41-1.41M2 12h8M22 12h-2M4.93 19.07l5.66-5.66M19.07 4.93l-1.41 1.41"/></svg>
</div>
<h3 class="tracks__card-title">Guide meg</h3>
<p class="tracks__card-desc">Strukturert wizard som leder deg gjennom intake, kapabilitetsvalg og eksport. Anbefalt for første gangs bruk eller når du er usikker.</p>
<div class="tracks__card-meta">
<span>56 klikk</span>
<span class="tracks__card-cta">Start →</span>
</div>
</a>
<a class="tracks__card tracks__card--explore" href="#">
<div class="tracks__card-icon">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg>
</div>
<h3 class="tracks__card-title">La meg utforske</h3>
<p class="tracks__card-desc">Bla i kapabilitetskatalogen, filtrér på lisens og dataresidens, og bygg arkitekturen din ad-hoc.</p>
<div class="tracks__card-meta">
<span>810 klikk</span>
<span class="tracks__card-cta">Bla →</span>
</div>
</a>
<a class="tracks__card tracks__card--expert" href="#">
<div class="tracks__card-icon">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>
</div>
<h3 class="tracks__card-title">Jeg vet hva jeg vil</h3>
<p class="tracks__card-desc">Hopp direkte til konfigurasjon, hent fra forrige beslutningsrekord, eller skriv inn JSON og la oss generere kommando-pipelinen.</p>
<div class="tracks__card-meta">
<span>34 klikk</span>
<span class="tracks__card-cta">Hopp inn →</span>
</div>
</a>
</div>
</div>
</section>
<!-- 22. FRIA rights-matrix -->
<section class="preview-section">
<div class="preview-section__heading">
<span class="preview-section__num">22</span>
<h2>FRIA rights-matrix</h2>
</div>
<p class="preview-section__intro">12 EU Charter-rettigheter × konsekvensnivå (05). Brukes i FRIA-vurdering (Art. 27 EU AI Act) for offentlig sektor høyrisiko-systemer.</p>
<div class="preview-section__demo">
<div class="rights-matrix">
<div class="rights-matrix__head">
<div class="rights-matrix__head-cell rights-matrix__head-cell--name">Grunnleggende rettighet (EU Charter)</div>
<div class="rights-matrix__head-cell">N/A</div>
<div class="rights-matrix__head-cell">Lav</div>
<div class="rights-matrix__head-cell">Med</div>
<div class="rights-matrix__head-cell">Høy</div>
<div class="rights-matrix__head-cell">Kritisk</div>
</div>
<div class="rights-matrix__row">
<div class="rights-matrix__name">Art. 7 — Rett til privatliv<span class="rights-matrix__name-meta">Korrespondanse, hjem, familieliv</span></div>
<div class="rights-matrix__cell" data-impact="0"></div>
<div class="rights-matrix__cell" data-impact="0"></div>
<div class="rights-matrix__cell" data-impact="0"></div>
<div class="rights-matrix__cell" data-impact="4"></div>
<div class="rights-matrix__cell" data-impact="0"></div>
</div>
<div class="rights-matrix__row">
<div class="rights-matrix__name">Art. 8 — Personopplysninger<span class="rights-matrix__name-meta">GDPR-forankret</span></div>
<div class="rights-matrix__cell" data-impact="0"></div>
<div class="rights-matrix__cell" data-impact="0"></div>
<div class="rights-matrix__cell" data-impact="0"></div>
<div class="rights-matrix__cell" data-impact="0"></div>
<div class="rights-matrix__cell" data-impact="5"></div>
</div>
<div class="rights-matrix__row">
<div class="rights-matrix__name">Art. 11 — Ytringsfrihet<span class="rights-matrix__name-meta">Innhentings- og spredningsfrihet</span></div>
<div class="rights-matrix__cell" data-impact="0"></div>
<div class="rights-matrix__cell" data-impact="1"></div>
<div class="rights-matrix__cell" data-impact="0"></div>
<div class="rights-matrix__cell" data-impact="0"></div>
<div class="rights-matrix__cell" data-impact="0"></div>
</div>
<div class="rights-matrix__row">
<div class="rights-matrix__name">Art. 21 — Diskrimineringsforbud<span class="rights-matrix__name-meta">Kjønn, etnisitet, religion, alder</span></div>
<div class="rights-matrix__cell" data-impact="0"></div>
<div class="rights-matrix__cell" data-impact="0"></div>
<div class="rights-matrix__cell" data-impact="0"></div>
<div class="rights-matrix__cell" data-impact="0"></div>
<div class="rights-matrix__cell" data-impact="5"></div>
</div>
<div class="rights-matrix__row">
<div class="rights-matrix__name">Art. 41 — God forvaltning<span class="rights-matrix__name-meta">Habilitet, begrunnelse, klagerett</span></div>
<div class="rights-matrix__cell" data-impact="0"></div>
<div class="rights-matrix__cell" data-impact="0"></div>
<div class="rights-matrix__cell" data-impact="0"></div>
<div class="rights-matrix__cell" data-impact="3"></div>
<div class="rights-matrix__cell" data-impact="0"></div>
</div>
<div class="rights-matrix__row">
<div class="rights-matrix__name">Art. 47 — Effektivt rettsmiddel<span class="rights-matrix__name-meta">Rett til rettferdig rettergang</span></div>
<div class="rights-matrix__cell" data-impact="0"></div>
<div class="rights-matrix__cell" data-impact="0"></div>
<div class="rights-matrix__cell" data-impact="2"></div>
<div class="rights-matrix__cell" data-impact="0"></div>
<div class="rights-matrix__cell" data-impact="0"></div>
</div>
</div>
<p class="text-xs text-tertiary" style="margin-top: var(--space-3);">Demo viser 6 av 12 rettigheter. Full FRIA dekker alle relevante artikler i EU-pakten.</p>
</div>
</section>
<!-- 23. Capability-matrix -->
<section class="preview-section">
<div class="preview-section__heading">
<span class="preview-section__num">23</span>
<h2>Capability-matrix</h2>
</div>
<p class="preview-section__intro">Brukes i ms-ai-architect for å mappe kapabilitet × lisens. Statuser: tilgjengelig, koster ekstra, betinget, mangler. Aldri kun farge — ikon + farge sammen.</p>
<div class="preview-section__demo">
<div class="capability-matrix" style="grid-template-columns: 1fr;">
<div class="capability-matrix__head" style="grid-template-columns: 2fr 1fr 1fr 1fr 1fr;">
<div class="capability-matrix__head-cell capability-matrix__head-cell--name">Kapabilitet</div>
<div class="capability-matrix__head-cell">M365 E3</div>
<div class="capability-matrix__head-cell">M365 E5</div>
<div class="capability-matrix__head-cell">Copilot</div>
<div class="capability-matrix__head-cell">Power Premium</div>
</div>
<div class="capability-matrix__row" style="grid-template-columns: 2fr 1fr 1fr 1fr 1fr;">
<div class="capability-matrix__name">Generer tekst i M365 Chat</div>
<div class="capability-matrix__cell" data-status="missing"><i class="capability-matrix__cell-icon"></i></div>
<div class="capability-matrix__cell" data-status="missing"><i class="capability-matrix__cell-icon"></i></div>
<div class="capability-matrix__cell" data-status="available"><i class="capability-matrix__cell-icon"></i></div>
<div class="capability-matrix__cell" data-status="missing"><i class="capability-matrix__cell-icon"></i></div>
</div>
<div class="capability-matrix__row" style="grid-template-columns: 2fr 1fr 1fr 1fr 1fr;">
<div class="capability-matrix__name">Sensitivity Labels på dokumenter</div>
<div class="capability-matrix__cell" data-status="cost"><i class="capability-matrix__cell-icon"></i></div>
<div class="capability-matrix__cell" data-status="available"><i class="capability-matrix__cell-icon"></i></div>
<div class="capability-matrix__cell" data-status="available"><i class="capability-matrix__cell-icon"></i></div>
<div class="capability-matrix__cell" data-status="missing"><i class="capability-matrix__cell-icon"></i></div>
</div>
<div class="capability-matrix__row" style="grid-template-columns: 2fr 1fr 1fr 1fr 1fr;">
<div class="capability-matrix__name">DLP for endpoints</div>
<div class="capability-matrix__cell" data-status="missing"><i class="capability-matrix__cell-icon"></i></div>
<div class="capability-matrix__cell" data-status="available"><i class="capability-matrix__cell-icon"></i></div>
<div class="capability-matrix__cell" data-status="conditional"><i class="capability-matrix__cell-icon"></i></div>
<div class="capability-matrix__cell" data-status="missing"><i class="capability-matrix__cell-icon"></i></div>
</div>
<div class="capability-matrix__row" style="grid-template-columns: 2fr 1fr 1fr 1fr 1fr;">
<div class="capability-matrix__name">Power Automate AI Builder-flows</div>
<div class="capability-matrix__cell" data-status="cost"><i class="capability-matrix__cell-icon"></i></div>
<div class="capability-matrix__cell" data-status="cost"><i class="capability-matrix__cell-icon"></i></div>
<div class="capability-matrix__cell" data-status="conditional"><i class="capability-matrix__cell-icon"></i></div>
<div class="capability-matrix__cell" data-status="available"><i class="capability-matrix__cell-icon"></i></div>
</div>
<div class="capability-matrix__row" style="grid-template-columns: 2fr 1fr 1fr 1fr 1fr;">
<div class="capability-matrix__name">Copilot Studio agent (custom)</div>
<div class="capability-matrix__cell" data-status="missing"><i class="capability-matrix__cell-icon"></i></div>
<div class="capability-matrix__cell" data-status="missing"><i class="capability-matrix__cell-icon"></i></div>
<div class="capability-matrix__cell" data-status="cost"><i class="capability-matrix__cell-icon"></i></div>
<div class="capability-matrix__cell" data-status="conditional"><i class="capability-matrix__cell-icon"></i></div>
</div>
</div>
<div class="capability-matrix__legend">
<span class="capability-matrix__legend-item"><i class="capability-matrix__cell-icon" style="background: var(--color-severity-low); color: #fff;"></i> Tilgjengelig</span>
<span class="capability-matrix__legend-item"><i class="capability-matrix__cell-icon" style="background: var(--color-severity-medium); color: #fff; font-size: 10px;">kr</i> Krever tilleggslisens</span>
<span class="capability-matrix__legend-item"><i class="capability-matrix__cell-icon" style="background: var(--color-severity-high); color: #fff;">!</i> Betinget (krever konfigurasjon)</span>
<span class="capability-matrix__legend-item"><i class="capability-matrix__cell-icon" style="background: var(--color-text-tertiary); color: #fff;">×</i> Ikke tilgjengelig</span>
</div>
</div>
</section>
<!-- 24. Parallel-agent-status -->
<section class="preview-section">
<div class="preview-section__heading">
<span class="preview-section__num">24</span>
<h2>Parallel-agent-status panel</h2>
</div>
<p class="preview-section__intro">Brukes i ms-ai-architect utredning (4 parallelle workers skriver til <code>.work/</code>) og ultraplan-local multi-wave execute. Per worker: tilstand, fremdrift og siste output-utdrag.</p>
<div class="preview-section__demo">
<div class="agent-grid">
<div class="agent-card">
<div class="agent-card__head">
<div>
<h4 class="agent-card__name">security-worker</h4>
<span class="agent-card__role">6×5 sikkerhetsmatrise</span>
</div>
<span class="agent-card__state" data-state="done"><span class="agent-card__state-dot"></span>Ferdig</span>
</div>
<div class="agent-card__progress"><div class="agent-card__progress-fill" style="width: 100%;"></div></div>
<div class="agent-card__metrics">
<span class="agent-card__metric"><span>Tid:</span><span class="agent-card__metric-value">2m 14s</span></span>
<span class="agent-card__metric"><span>Funn:</span><span class="agent-card__metric-value">12</span></span>
</div>
</div>
<div class="agent-card">
<div class="agent-card__head">
<div>
<h4 class="agent-card__name">cost-worker</h4>
<span class="agent-card__role">P10/P50/P90 NOK-estimat</span>
</div>
<span class="agent-card__state" data-state="running"><span class="agent-card__state-dot"></span>Kjører</span>
</div>
<div class="agent-card__progress"><div class="agent-card__progress-fill" style="width: 67%;"></div></div>
<div class="agent-card__metrics">
<span class="agent-card__metric"><span>Tid:</span><span class="agent-card__metric-value">1m 32s</span></span>
<span class="agent-card__metric"><span>SKU-er:</span><span class="agent-card__metric-value">8 / 12</span></span>
</div>
</div>
<div class="agent-card">
<div class="agent-card__head">
<div>
<h4 class="agent-card__name">dpia-worker</h4>
<span class="agent-card__role">GDPR Art. 35-vurdering</span>
</div>
<span class="agent-card__state" data-state="running"><span class="agent-card__state-dot"></span>Kjører</span>
</div>
<div class="agent-card__progress"><div class="agent-card__progress-fill" style="width: 23%;"></div></div>
<div class="agent-card__metrics">
<span class="agent-card__metric"><span>Tid:</span><span class="agent-card__metric-value">42s</span></span>
<span class="agent-card__metric"><span>Risiko:</span><span class="agent-card__metric-value">2 / 10</span></span>
</div>
</div>
<div class="agent-card">
<div class="agent-card__head">
<div>
<h4 class="agent-card__name">diagram-worker</h4>
<span class="agent-card__role">Imagen 3 / Mermaid fallback</span>
</div>
<span class="agent-card__state" data-state="failed"><span class="agent-card__state-dot"></span>Feilet</span>
</div>
<div class="agent-card__progress"><div class="agent-card__progress-fill" style="width: 100%; background: var(--color-state-failed);"></div></div>
<div class="agent-card__metrics">
<span class="agent-card__metric"><span>Feil:</span><span class="agent-card__metric-value" style="color: var(--color-state-failed);">MCP timeout</span></span>
</div>
</div>
</div>
</div>
</section>
<!-- 25. ErrorSummary -->
<section class="preview-section">
<div class="preview-section__heading">
<span class="preview-section__num">25</span>
<h2>ErrorSummary (Aksel/GOV.UK)</h2>
</div>
<p class="preview-section__intro">Konsentrert valideringsfeil-liste øverst i lange skjemaer. Hver feil har anker-link til feltet. Skjermlesere leser hele listen først — kritisk for tilgjengelig skjema-UX.</p>
<div class="preview-section__demo">
<div class="error-summary" role="alert" aria-labelledby="es-heading">
<h3 class="error-summary__heading" id="es-heading">Det er 4 feil i ROS-skjemaet</h3>
<p class="error-summary__body">Rett opp feilene før du fortsetter. Hver feil lenker til feltet.</p>
<ul class="error-summary__list">
<li class="error-summary__item"><a class="error-summary__link" href="#field-system">System-navn må fylles ut</a></li>
<li class="error-summary__item"><a class="error-summary__link" href="#field-residency">Dataresidens er påkrevd for offentlig sektor (velg EU eller Norway East)</a></li>
<li class="error-summary__item"><a class="error-summary__link" href="#field-threats">Minst 5 trusler må plasseres i matrisen før du kan generere rapport</a></li>
<li class="error-summary__item"><a class="error-summary__link" href="#field-owner">Behandlingsansvarlig må navngis (rolle eller person)</a></li>
</ul>
</div>
</div>
</section>
<!-- 26. GuidePanel -->
<section class="preview-section">
<div class="preview-section__heading">
<span class="preview-section__num">26</span>
<h2>GuidePanel (Aksel)</h2>
</div>
<p class="preview-section__intro">Vennlig inline-veiledning for første-gangs-brukere. Skala av hjelp uten å være skoleflink.</p>
<div class="preview-section__demo stack">
<div class="guide-panel guide-panel--info">
<div class="guide-panel__icon" aria-hidden="true">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4M12 8h.01"/></svg>
</div>
<div class="guide-panel__body">
<h4 class="guide-panel__title">Første gang du gjør en ROS for AI?</h4>
<p class="guide-panel__text">Vi følger NS 5814:2021 og bruker "evalueringskriterier" (ikke "akseptkriterier"). De 49 forhåndsdefinerte truslene er hentet fra EU AI Act Annex III og NSM grunnprinsipper for IKT-sikkerhet.</p>
</div>
<a href="#" class="btn btn--secondary btn--sm guide-panel__action">Les metodikk</a>
</div>
<div class="guide-panel guide-panel--success">
<div class="guide-panel__icon" aria-hidden="true">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>
</div>
<div class="guide-panel__body">
<h4 class="guide-panel__title">Onboarding fullført</h4>
<p class="guide-panel__text">Profilen din er lagret i <code>org/profile.md</code>. Alle agenter (security, cost, dpia, diagram) leser denne automatisk — du slipper å skrive om virksomheten på nytt.</p>
</div>
</div>
<div class="guide-panel guide-panel--warn">
<div class="guide-panel__icon" aria-hidden="true">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
</div>
<div class="guide-panel__body">
<h4 class="guide-panel__title">Schrems II-flagging</h4>
<p class="guide-panel__text">Du har valgt en region som ikke er EU/EØS. For offentlig sektor i Norge krever dette rettslig vurdering av overføringsmekanismen (SCCs + supplementary measures eller Microsoft EU Data Boundary).</p>
</div>
<a href="#" class="btn btn--secondary btn--sm guide-panel__action">Vis vurderingsmal</a>
</div>
</div>
</section>
<div style="padding: var(--space-12) 0; text-align: center; color: var(--color-text-tertiary); font-size: var(--font-size-sm);">
<p>Hvis disse 8 ser ut som de hører til familien: behold dem. Hvis ikke: scrap og kjør alle 20 i claude.ai/design.</p>
<p style="margin-top: var(--space-2);"><a href="index.html">← Til hovedoversikt</a></p>
</div>
</main>
<script>
const themeToggle = document.getElementById('themeToggle');
const root = document.documentElement;
const saved = localStorage.getItem('pgds-theme') || 'light';
root.dataset.theme = saved;
themeToggle.textContent = saved === 'dark' ? 'Lys modus' : 'Mørk modus';
themeToggle.addEventListener('click', () => {
const next = root.dataset.theme === 'dark' ? 'light' : 'dark';
root.dataset.theme = next;
localStorage.setItem('pgds-theme', next);
themeToggle.textContent = next === 'dark' ? 'Lys modus' : 'Mørk modus';
});
</script>
</body>
</html>