ktg-plugin-marketplace/shared/playground-examples/templates.html
Kjell Tore Guttormsen 4a2bf3567a feat(shared): add Playground design system v0.1 with Tier 1+2 components
Aksel/Digdir-aligned design system for plugin Playgrounds — visual self-service
UIs that complement terminal slash-commands. Targets ms-ai-architect, okr,
llm-security, ultraplan-local, config-audit. Built for Norwegian public sector
decision-makers plus developer power-users — one visual family, two info
densities.

Generated by claude.ai/design (Anthropic) in a dialog-based design session
driven by a comprehensive brief covering all five target plugins, Aksel/Digdir
conventions, and domain-specific visual standards (NS 5814 ROS matrices, EU AI
Act 4-tier pyramide, Doerr OKR scoring, NIST CSF, OWASP threat modeling).
Per Anthropic Consumer Terms §4, ownership of outputs is assigned to the user;
licensed MIT.

shared/playground-design-system/ (5874 lines CSS + JSON):
- tokens.css: Inter font, Digdir blue #0062BA, deuteranopia-safe severity ramp,
  distinct severity-red (#A40E26) vs failure-red (#7D1A1A), plugin scope colors,
  light + dark themes
- base.css: reset, typography (17px body, 65ch measure), focus rings, buttons,
  badges, forms, Aksel 3-tier inline messages, prefers-reduced-motion support
- components.css: Tier 1 — radar/spider, 5x5 matrix-heatmap (bottom-left
  origin, ROS/DPIA), findings-browser, critique-card, wizard/stepper,
  live-meter with antipattern lints
- components-tier2.css: Tier 2 — decision-tree, traffic-lights with rationale,
  diff-review, treemap, distribution P10/P50/P90, command-pipeline output, AI
  Act 4-color pyramide, pipeline-cockpit, verdict-pill + 5-band risk-meter,
  codepoint-reveal (Unicode steg), small-multiples grid (16-cat posture),
  OWASP badges (LLM/ASI/AST/MCP)
- print.css: A4 stylesheet with BW severity hatching, kommune-logo slot,
  signature lines for offentlige dokumenter
- schemas/: finding.schema.json, okr-set.schema.json, ros-threat.schema.json
- README.md: usage guide, design principles, component reference, provenance

shared/playground-examples/:
- index.html: system showcase with all components live
- ros-lier-kommune.html: Lier kommune Copilot ROS-rapport (Scenario A)
- okr-baerum.html: Baerum kommune T2-2026 OKR live writer (Scenario B)
- security-vegvesen.html: SVV ToxicSkills findings review, 85 funn BLOCK
  (Scenario C)
- templates.html: A4 print template demos
- ros-app.js + ros-data.js: Scenario A interactivity

WCAG 2.1 AA throughout (UU-loven krav for offentlig sektor): focus rings, ARIA
attributes, keyboard navigation, severity numerical redundancy for deuteranopia
and BW print, semantic HTML.

Known limitation: Inter loaded via Google Fonts CDN violates self-contained
no-CDN constraint. System-stack fallback works offline. Self-host woff2 files
in Phase 2.
2026-05-02 06:59:19 +02:00

465 lines
28 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="nb">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Templates · 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/print.css" />
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<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>
.page { padding: var(--space-8) 0 var(--space-16); }
.tpl-grid { display: grid; grid-template-columns: 240px 1fr; gap: var(--space-8); align-items: start; }
.tpl-nav { position: sticky; top: var(--space-4); display: flex; flex-direction: column; gap: 2px; }
.tpl-nav a {
padding: 8px 12px; font-size: var(--font-size-sm);
color: var(--color-text-secondary); text-decoration: none;
border-radius: var(--radius-sm); border-left: 2px solid transparent;
}
.tpl-nav a:hover { background: var(--color-bg-soft); color: var(--color-text-primary); }
.tpl-nav a[aria-current="true"] { background: var(--color-primary-50); color: var(--color-primary-700); border-left-color: var(--color-primary-500); font-weight: var(--font-weight-medium); }
.tpl-nav__heading { font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--color-text-tertiary); padding: 6px 12px; margin-top: var(--space-3); }
.tpl-nav__heading:first-child { margin-top: 0; }
.tpl { margin-bottom: var(--space-12); padding-bottom: var(--space-8); border-bottom: 1px solid var(--color-border-subtle); }
.tpl__head { display: flex; justify-content: space-between; align-items: flex-end; margin-bottom: var(--space-4); }
.tpl__title { display: flex; flex-direction: column; gap: 4px; }
.tpl__title h2 { font-size: var(--font-size-2xl); margin: 0; }
.tpl__eyebrow { font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--color-text-tertiary); font-weight: var(--font-weight-semibold); }
.tpl__lede { color: var(--color-text-secondary); font-size: var(--font-size-sm); margin-top: 4px; max-width: var(--measure); }
.tpl__demo {
background: var(--color-bg-soft);
border: 1px solid var(--color-border-subtle);
border-radius: var(--radius-md);
padding: var(--space-6);
margin-bottom: var(--space-3);
}
.tpl__code {
background: #1F2328; color: #E6E6E6;
border-radius: var(--radius-md);
padding: var(--space-4);
font-family: var(--font-family-mono);
font-size: 12px;
line-height: 1.55;
overflow-x: auto;
white-space: pre;
max-height: 320px;
overflow-y: auto;
}
.tpl__copy {
display: flex; justify-content: space-between; align-items: center;
padding: 6px 10px;
background: #2A2F36; color: #C2C8D0;
font-size: 11px; font-family: var(--font-family-mono);
border-radius: var(--radius-md) var(--radius-md) 0 0;
margin-bottom: 0;
}
.tpl__copy + .tpl__code { border-radius: 0 0 var(--radius-md) var(--radius-md); }
.tpl__copy button {
background: transparent; border: 1px solid #3A3F47; color: #C2C8D0;
padding: 3px 8px; border-radius: 3px; font-size: 11px; cursor: pointer; font-family: inherit;
}
.tpl__copy button:hover { background: #3A3F47; }
.pg-print-preview-banner {
background: var(--color-bg-soft); border: 1px solid var(--color-border-subtle); padding: var(--space-3) var(--space-4);
border-radius: var(--radius-md); display: flex; gap: var(--space-3); align-items: center;
margin-bottom: var(--space-4); font-size: var(--font-size-sm);
}
/* A4-preview emulator (skjerm) */
.a4-preview {
background: #ddd;
padding: var(--space-6);
border-radius: var(--radius-md);
overflow: auto;
}
.a4-page {
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-family: "Inter", sans-serif;
font-size: 11pt;
line-height: 1.45;
color: #000;
transform: scale(0.72); transform-origin: top center;
}
@media (max-width: 980px) {
.tpl-grid { grid-template-columns: 1fr; }
.tpl-nav { position: static; }
}
</style>
</head>
<body>
<header class="app-header">
<a href="index.html" class="app-header__brand">
<span class="app-header__brand-mark">P</span>
<span>Playground Design System</span>
</a>
<span class="app-header__breadcrumb"><span aria-hidden="true">/</span> Templates</span>
<span class="app-header__spacer"></span>
<a href="index.html" class="btn btn--ghost btn--sm">← Til oversikt</a>
</header>
<main class="container container--wide page">
<div class="tpl-grid">
<!-- NAV -->
<nav class="tpl-nav" aria-label="Templates">
<span class="tpl-nav__heading">HTML-startere</span>
<a href="#skeleton" aria-current="true">Skeleton</a>
<a href="#intake-wizard">Intake-wizard</a>
<a href="#single-report">Single-report</a>
<a href="#findings-review">Findings-review</a>
<a href="#live-writer">Live-writer</a>
<span class="tpl-nav__heading">Print &amp; data</span>
<a href="#a4-print">A4-rapport (print)</a>
<a href="#schemas">JSON-skjemaer</a>
</nav>
<!-- CONTENT -->
<div>
<div style="margin-bottom: var(--space-8);">
<span style="font-size: 11px; text-transform: uppercase; letter-spacing: 0.1em; color: var(--color-text-tertiary); font-weight: var(--font-weight-semibold);">Fase 3 · Templates</span>
<h1 style="margin: 4px 0 8px; font-size: var(--font-size-3xl);">Copy-paste startere for nye plugins</h1>
<p style="color: var(--color-text-secondary); max-width: 65ch; font-size: var(--font-size-md);">
Hver template er minst mulig HTML som korrekt importerer designsystemet og bruker etablerte mønstre.
Forke en plugin? Start fra én av disse, ikke fra blank fil.
</p>
</div>
<!-- ============================================== -->
<!-- SKELETON -->
<!-- ============================================== -->
<section class="tpl" id="skeleton">
<div class="tpl__head">
<div class="tpl__title">
<span class="tpl__eyebrow">Template 01</span>
<h2>Skeleton — minimal HTML-side</h2>
<p class="tpl__lede">Bare designsystemet importert. Container, header, og en tom <code>main</code>. Bruk når du vil bygge noe helt eget med tokens og base-styling.</p>
</div>
<span class="badge badge--soft">~ 30 linjer</span>
</div>
<div class="tpl__copy"><span>scenarios/&lt;ditt-scenario&gt;.html</span><button onclick="copyCode(this)">Kopier</button></div>
<pre class="tpl__code">&lt;!doctype html&gt;
&lt;html lang="nb"&gt;
&lt;head&gt;
&lt;meta charset="utf-8" /&gt;
&lt;meta name="viewport" content="width=device-width, initial-scale=1" /&gt;
&lt;title&gt;Min plugin — &lt;org&gt;&lt;/title&gt;
&lt;link rel="stylesheet" href="../playground-design-system/tokens.css" /&gt;
&lt;link rel="stylesheet" href="../playground-design-system/base.css" /&gt;
&lt;link rel="stylesheet" href="../playground-design-system/components.css" /&gt;
&lt;link rel="stylesheet" href="../playground-design-system/components-tier2.css" /&gt;
&lt;link rel="stylesheet" href="../playground-design-system/print.css" /&gt;
&lt;link rel="preconnect" href="https://fonts.googleapis.com"&gt;
&lt;link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&amp;family=JetBrains+Mono:wght@400;500;600&amp;display=swap" rel="stylesheet"&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;header class="app-header"&gt;
&lt;a href="index.html" class="app-header__brand"&gt;
&lt;span class="app-header__brand-mark"&gt;P&lt;/span&gt;
&lt;span&gt;Min plugin&lt;/span&gt;
&lt;/a&gt;
&lt;span class="app-header__breadcrumb"&gt;/ &lt;org&gt;&lt;/span&gt;
&lt;/header&gt;
&lt;main class="container container--wide" style="padding: var(--space-8) 0;"&gt;
&lt;h1&gt;Tittel&lt;/h1&gt;
&lt;p class="text-secondary"&gt;Innhold her.&lt;/p&gt;
&lt;/main&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
</section>
<!-- ============================================== -->
<!-- INTAKE WIZARD -->
<!-- ============================================== -->
<section class="tpl" id="intake-wizard">
<div class="tpl__head">
<div class="tpl__title">
<span class="tpl__eyebrow">Template 02</span>
<h2>Intake-wizard</h2>
<p class="tpl__lede">Fire-stegs onboarding. Sticky stepper, valideringsgate framover, localStorage-persistens. Brukes for ROS-intake, OKR-onboarding, security-clean.</p>
</div>
<span class="badge badge--soft">scenarios/ros-lier-kommune.html (skjerm 1)</span>
</div>
<div class="tpl__demo">
<nav class="stepper" style="margin-bottom: 0; border-bottom: none; padding-bottom: 0;">
<button type="button" class="stepper__step" data-state="complete">
<span class="stepper__step-number"><span class="stepper__step-number-text">1</span></span>
<span class="stepper__step-text"><span class="stepper__step-label">Org-profil</span><span class="stepper__step-hint">Ferdig</span></span>
</button>
<button type="button" class="stepper__step" data-state="active">
<span class="stepper__step-number"><span class="stepper__step-number-text">2</span></span>
<span class="stepper__step-text"><span class="stepper__step-label">System</span><span class="stepper__step-hint">Pågår</span></span>
</button>
<button type="button" class="stepper__step" data-state="pending">
<span class="stepper__step-number"><span class="stepper__step-number-text">3</span></span>
<span class="stepper__step-text"><span class="stepper__step-label">Compliance</span><span class="stepper__step-hint">Venter</span></span>
</button>
<button type="button" class="stepper__step" data-state="pending">
<span class="stepper__step-number"><span class="stepper__step-number-text">4</span></span>
<span class="stepper__step-text"><span class="stepper__step-label">Bekreft</span><span class="stepper__step-hint">Venter</span></span>
</button>
</nav>
</div>
<p style="font-size: 12px; color: var(--color-text-tertiary); font-family: var(--font-family-mono);">→ Se <a href="../scenarios/ros-lier-kommune.html#intake">ros-lier-kommune.html#intake</a> for full implementasjon med skjema-felt og validering.</p>
</section>
<!-- ============================================== -->
<!-- SINGLE REPORT -->
<!-- ============================================== -->
<section class="tpl" id="single-report">
<div class="tpl__head">
<div class="tpl__title">
<span class="tpl__eyebrow">Template 03</span>
<h2>Single-report</h2>
<p class="tpl__lede">Én rapport, fire seksjoner: header med metadata + verdict-pill, hovedinnhold, sidefelt, signatur. Bygd for projector-bruk og PDF-eksport.</p>
</div>
<span class="badge badge--soft">scenarios/security-vegvesen.html</span>
</div>
<div class="tpl__demo" style="background: #fff; padding: var(--space-5);">
<div style="display: grid; grid-template-columns: 1fr auto; gap: var(--space-5); align-items: start; padding-bottom: var(--space-4); border-bottom: 1px solid var(--color-border-subtle);">
<div>
<span style="font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--color-scope-architect); font-weight: var(--font-weight-semibold);">Eyebrow · scope</span>
<h3 style="margin: 4px 0 6px; font-size: var(--font-size-xl);">Rapporttittel</h3>
<div style="display: flex; gap: var(--space-3); font-size: var(--font-size-sm); color: var(--color-text-secondary);">
<span><span style="font-size: 11px; color: var(--color-text-tertiary); text-transform: uppercase; letter-spacing: 0.06em;">Eier</span> Person</span>
<span><span style="font-size: 11px; color: var(--color-text-tertiary); text-transform: uppercase; letter-spacing: 0.06em;">Dato</span> 02. mai</span>
</div>
</div>
<span class="verdict-pill-lg" data-verdict="warning" style="padding: 8px 14px;">
<span class="verdict-pill-lg__verdict" style="font-size: var(--font-size-md);">WARN</span>
<span class="verdict-pill-lg__sub">Manuell gjennomgang</span>
</span>
</div>
<div style="display: grid; grid-template-columns: 1fr 220px; gap: var(--space-5); margin-top: var(--space-4);">
<div>
<h4 style="font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--color-text-tertiary); margin: 0 0 8px;">Sammendrag</h4>
<p style="font-size: var(--font-size-sm); color: var(--color-text-secondary); margin: 0;">Hovedinnhold går her — typisk 2-4 avsnitt med mellomtitler.</p>
</div>
<aside style="padding-left: var(--space-4); border-left: 1px solid var(--color-border-subtle); font-size: 12px; color: var(--color-text-secondary);">
<strong>Kort fakta</strong><br>
Sidekontekst, henvisninger, neste-steg.
</aside>
</div>
</div>
</section>
<!-- ============================================== -->
<!-- FINDINGS REVIEW -->
<!-- ============================================== -->
<section class="tpl" id="findings-review">
<div class="tpl__head">
<div class="tpl__title">
<span class="tpl__eyebrow">Template 04</span>
<h2>Findings-review</h2>
<p class="tpl__lede">Posture-grid + filter-bar + finding-kort + tiltaksplan. Strukturen i Scenario C i konsentrert form.</p>
</div>
<span class="badge badge--soft">scenarios/security-vegvesen.html</span>
</div>
<div class="tpl__demo" style="background: var(--color-surface);">
<div class="filter-bar" style="margin-bottom: var(--space-4);">
<div class="filter-bar__group">
<span class="filter-bar__label">Alvorlighet</span>
<button class="chip" aria-pressed="true">Alle <span class="chip__count">12</span></button>
<button class="chip" aria-pressed="false">Kritisk <span class="chip__count">2</span></button>
<button class="chip" aria-pressed="false">Høy <span class="chip__count">3</span></button>
</div>
</div>
<article class="finding" data-sev="high" style="margin-bottom: 0;">
<header class="finding__head">
<div>
<div class="finding__id">PROJEKT-123 · F-001</div>
<h3 class="finding__title" style="font-size: var(--font-size-md);">Funn-tittel</h3>
</div>
<div></div>
<div class="finding__badges">
<span class="rule-badge badge--owasp-llm">RULE01</span>
<span class="badge" style="background: var(--color-severity-high); color: #fff;">Høy</span>
</div>
</header>
<div class="finding__body" style="padding: var(--space-3) var(--space-4);">
<p style="margin: 0; font-size: var(--font-size-sm); color: var(--color-text-secondary);">Kort beskrivelse av funnet. Full struktur med kildekontekst, anbefaling og side-felt finnes i Scenario C.</p>
</div>
</article>
</div>
</section>
<!-- ============================================== -->
<!-- LIVE WRITER -->
<!-- ============================================== -->
<section class="tpl" id="live-writer">
<div class="tpl__head">
<div class="tpl__title">
<span class="tpl__eyebrow">Template 05</span>
<h2>Live-writer</h2>
<p class="tpl__lede">To-pane: editor med inline highlights til venstre, kritikk-stack til høyre. Score-strip øverst. Fire view-modi: skriv / sammenlign / kohort / endelig.</p>
</div>
<span class="badge badge--soft">scenarios/okr-baerum.html</span>
</div>
<div class="tpl__demo" style="padding: var(--space-4);">
<div style="display: grid; grid-template-columns: 1.4fr 1fr; gap: var(--space-4);">
<div style="background: #fff; border: 1px solid var(--color-border-subtle); border-radius: var(--radius-md); padding: var(--space-3);">
<div style="font-size: 11px; color: var(--color-text-tertiary); text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 6px;">Editor</div>
<p style="margin: 0; font-family: var(--font-family-serif); font-size: 16px; line-height: 1.55;">
Innhold med <span style="background-image: linear-gradient(transparent 60%, rgba(204,90,0,0.22) 60%); border-bottom: 2px solid var(--color-severity-high); padding-bottom: 1px;">inline highlight</span> som lenker til kritikk-kortet til høyre.
</p>
</div>
<div style="background: #fff; border: 1px solid var(--color-primary-500); border-radius: var(--radius-md); padding: var(--space-3); box-shadow: 0 0 0 2px var(--color-primary-100);">
<div style="display: flex; gap: 8px; align-items: center; margin-bottom: 4px;">
<span style="width: 8px; height: 8px; border-radius: 50%; background: var(--color-severity-high);"></span>
<strong style="font-size: var(--font-size-sm);">Kritikk-tittel</strong>
</div>
<p style="margin: 0 0 8px; font-size: 12px; color: var(--color-text-secondary); line-height: 1.5;">Kort forklaring og forslag til omskriving.</p>
<button class="btn btn--primary btn--sm">Bruk forslag</button>
</div>
</div>
</div>
</section>
<!-- ============================================== -->
<!-- A4 PRINT -->
<!-- ============================================== -->
<section class="tpl" id="a4-print">
<div class="tpl__head">
<div class="tpl__title">
<span class="tpl__eyebrow">Template 06 · Print</span>
<h2>A4-rapport · offentlig dokument</h2>
<p class="tpl__lede">Skraverings-mønstre i stedet for farge for B/W-utskrift. Header med kommune-logo-slot og signaturfelt. Importer <code>print.css</code> og legg innhold i en <code>.a4</code>-wrapper for skjerm-preview.</p>
</div>
<button class="btn btn--secondary btn--sm" onclick="window.print()">Skriv ut nå</button>
</div>
<div class="pg-print-preview-banner">
<span style="font-size: 18px;">📄</span>
<span>Slik ser dokumentet ut på A4. <kbd style="background: var(--color-bg-soft); border: 1px solid var(--color-border-moderate); border-radius: 3px; padding: 1px 5px; font-family: var(--font-family-mono); font-size: 11px;">Cmd/Ctrl + P</kbd> for ekte print-preview.</span>
</div>
<div class="a4-preview">
<div class="a4-page" id="a4-demo">
<div class="print-header" style="display: grid; grid-template-columns: auto 1fr; gap: 14pt; align-items: center; padding-bottom: 10pt; margin-bottom: 16pt; border-bottom: 0.5pt solid #888;">
<div class="print-header__logo" style="width: 40pt; height: 40pt; border: 0.5pt solid #888; display: flex; align-items: center; justify-content: center; font-size: 9pt; color: #888;">[logo]</div>
<div>
<div style="font-size: 9pt; color: #555; text-transform: uppercase; letter-spacing: 0.06em;">Lier kommune · IT-styring</div>
<div style="font-size: 14pt; font-weight: 600; margin: 2pt 0;">Risiko- og sårbarhetsanalyse · M365 Copilot</div>
<div style="font-size: 9pt; color: #555;"><strong>ROS-2026-LIER-COPILOT-01</strong> · 02. mai 2026 · Eier: Eli Bjerke</div>
</div>
</div>
<h2 style="font-size: 12pt; margin: 12pt 0 4pt;">Sammendrag</h2>
<p style="font-size: 10pt; line-height: 1.45; margin: 0 0 8pt;">M365 Copilot foreslås innført for 1 850 ansatte. Analysen identifiserte 49 trusler, hvorav 4 ligger i kritisk sone og 12 i høy sone før mitigerende tiltak. Anbefalingen er <strong>GO med fire betingelser</strong> beskrevet i kap. 6.</p>
<h2 style="font-size: 12pt; margin: 12pt 0 4pt;">Risiko-matrise (5×5)</h2>
<table style="border-collapse: collapse; width: 100%; font-size: 9pt; margin-bottom: 8pt;">
<thead>
<tr><th style="padding: 4pt; border-bottom: 0.5pt solid #000; text-align: left;">Sone</th><th style="padding: 4pt; border-bottom: 0.5pt solid #000;">Mønster</th><th style="padding: 4pt; border-bottom: 0.5pt solid #000;">Antall trusler</th></tr>
</thead>
<tbody>
<tr><td style="padding: 4pt;">Lav (14)</td><td style="padding: 4pt;"><span style="display: inline-block; width: 18pt; height: 10pt; background: #fff; border: 0.5pt solid #000; vertical-align: middle;"></span></td><td style="padding: 4pt;">21</td></tr>
<tr><td style="padding: 4pt;">Moderat (58)</td><td style="padding: 4pt;"><span style="display: inline-block; width: 18pt; height: 10pt; background: repeating-linear-gradient(45deg, #000 0 0.5pt, transparent 0.5pt 4pt); border: 0.5pt solid #000; vertical-align: middle;"></span></td><td style="padding: 4pt;">12</td></tr>
<tr><td style="padding: 4pt;">Høy (912)</td><td style="padding: 4pt;"><span style="display: inline-block; width: 18pt; height: 10pt; background: repeating-linear-gradient(45deg, #000 0 0.7pt, transparent 0.7pt 3pt); border: 0.5pt solid #000; vertical-align: middle;"></span></td><td style="padding: 4pt;">12</td></tr>
<tr><td style="padding: 4pt;">Kritisk (1520)</td><td style="padding: 4pt;"><span style="display: inline-block; width: 18pt; height: 10pt; background: repeating-linear-gradient(45deg, #000 0 1pt, transparent 1pt 2pt); border: 0.5pt solid #000; vertical-align: middle;"></span></td><td style="padding: 4pt;">3</td></tr>
<tr><td style="padding: 4pt;">Ekstrem (25)</td><td style="padding: 4pt;"><span style="display: inline-block; width: 18pt; height: 10pt; background: #000; border: 0.5pt solid #000; vertical-align: middle;"></span></td><td style="padding: 4pt;">1</td></tr>
</tbody>
</table>
<h2 style="font-size: 12pt; margin: 12pt 0 4pt;">Anbefaling</h2>
<p style="font-size: 10pt; line-height: 1.45; margin: 0 0 8pt;">GO med fire betingelser: (1) DLP-policy aktivert i tenant før utrulling. (2) Sensitivity Labels innført i alle arkivsystem. (3) Schrems II-vurdering ferdigstilt for cross-tenant. (4) Innbygger-tilfredshetsmåling baseline T1.</p>
<div class="print-footer" style="margin-top: 24pt; padding-top: 10pt; border-top: 0.5pt solid #888; display: grid; grid-template-columns: 1fr 1fr; gap: 18pt; font-size: 9pt;">
<div class="print-signature">
<div class="print-signature__line" style="border-bottom: 0.5pt solid #000; height: 28pt;"></div>
<div class="print-signature__caption" style="font-size: 9pt; color: #555;">Eli Bjerke · IT-sikkerhetsleder · dato</div>
</div>
<div class="print-signature">
<div class="print-signature__line" style="border-bottom: 0.5pt solid #000; height: 28pt;"></div>
<div class="print-signature__caption" style="font-size: 9pt; color: #555;">Kommunaldirektør · dato</div>
</div>
</div>
</div>
</div>
</section>
<!-- ============================================== -->
<!-- SCHEMAS -->
<!-- ============================================== -->
<section class="tpl" id="schemas">
<div class="tpl__head">
<div class="tpl__title">
<span class="tpl__eyebrow">Datakontrakter</span>
<h2>JSON-skjemaer</h2>
<p class="tpl__lede">Tre skjemaer som lar plugins utveksle data uten gjetting. Validér med vanilig <code>ajv</code> eller VS Codes innebygde schema-validator.</p>
</div>
</div>
<div style="display: grid; grid-template-columns: 1fr 1fr 1fr; gap: var(--space-3);">
<a class="card" style="text-decoration: none; color: inherit; display: flex; flex-direction: column; gap: 6px;" href="../playground-design-system/schemas/finding.schema.json">
<span style="font-size: 11px; color: var(--color-text-tertiary); text-transform: uppercase; letter-spacing: 0.06em;">Schema</span>
<strong>finding.schema.json</strong>
<span style="font-size: 12px; color: var(--color-text-secondary);">Ett funn fra en skanning. severity, source, evidence, recommendation, status.</span>
<span style="font-family: var(--font-family-mono); font-size: 11px; color: var(--color-text-tertiary); margin-top: auto;">llm-security · config-audit · ms-ai-review · ultraplan-review</span>
</a>
<a class="card" style="text-decoration: none; color: inherit; display: flex; flex-direction: column; gap: 6px;" href="../playground-design-system/schemas/okr-set.schema.json">
<span style="font-size: 11px; color: var(--color-text-tertiary); text-transform: uppercase; letter-spacing: 0.06em;">Schema</span>
<strong>okr-set.schema.json</strong>
<span style="font-size: 12px; color: var(--color-text-secondary);">Objective + 16 nøkkelresultater. baseline/target/stretch, period, score, critiques.</span>
<span style="font-family: var(--font-family-mono); font-size: 11px; color: var(--color-text-tertiary); margin-top: auto;">OKR live-writer</span>
</a>
<a class="card" style="text-decoration: none; color: inherit; display: flex; flex-direction: column; gap: 6px;" href="../playground-design-system/schemas/ros-threat.schema.json">
<span style="font-size: 11px; color: var(--color-text-tertiary); text-transform: uppercase; letter-spacing: 0.06em;">Schema</span>
<strong>ros-threat.schema.json</strong>
<span style="font-size: 12px; color: var(--color-text-secondary);">NS 5814-justert trussel. inherent + residual, controls (M-001…), regulatory_refs.</span>
<span style="font-family: var(--font-family-mono); font-size: 11px; color: var(--color-text-tertiary); margin-top: auto;">ms-ai-architect</span>
</a>
</div>
<p style="font-size: 12px; color: var(--color-text-tertiary); margin-top: var(--space-4);">Bruk i HTML/JS: <code>fetch('/shared/playground-design-system/schemas/finding.schema.json').then(r =&gt; r.json())</code></p>
</section>
</div>
</div>
</main>
<script>
// smooth nav
document.querySelectorAll('.tpl-nav a').forEach(a => {
a.addEventListener('click', () => {
document.querySelectorAll('.tpl-nav a').forEach(x => x.removeAttribute('aria-current'));
a.setAttribute('aria-current', 'true');
});
});
function copyCode(btn) {
const code = btn.closest('.tpl').querySelector('.tpl__code').textContent;
navigator.clipboard?.writeText(code).then(() => {
const orig = btn.textContent;
btn.textContent = 'Kopiert!';
setTimeout(() => { btn.textContent = orig; }, 1400);
});
}
</script>
</body>
</html>