ktg-plugin-marketplace/shared/playground-examples/templates.html
Kjell Tore Guttormsen f1fecf39b8 feat(shared): Tier 3 wave 2 (12 components) + self-hosted fonts
Two changes in one commit because they were prepared together and the
component demos depend on the new self-hosted fonts.css.

Tier 3 wave 2 — 12 new components
---------------------------------
Adds components-tier3-supplement.css (886 lines) and 12 isolated demo
HTML pages under shared/playground-examples/components/:
toxic-flow chain, fleet-overview, kanban Keep/Review/Remove,
maturity-ladder, classify-and-transform, cycle-ribbon,
persistent-antipattern, suppressed-signals, ExpansionCard, ReadMore,
FormProgress, Aspirational-vs-Committed.

Reuses existing tokens — no new CSS custom properties. Honors the
Phase 1 feedback rules: no large pink areas for body text, severity-red
distinct from failure-red, dark mode via existing [data-theme="dark"].

Provenance: components-tier3-supplement.css and the 12 demo bodies were
authored by claude.ai/design (separate Anthropic instance) on 2026-05-03.
This commit only integrates them — path rewrites, font swap, generic
name substitution in fleet-overview demo data, README updates.
base.css from the export was deliberately NOT taken in because it
reverted the inline-message contrast fix from v0.1.

Self-hosted fonts (Inter, JetBrains Mono, Source Serif 4)
---------------------------------------------------------
Replaces all fonts.googleapis.com / fonts.gstatic.com requests with
.woff2 files bundled at shared/playground-design-system/fonts/.

Why:
- No data leaked to Google about end-user IPs and User-Agents.
- GDPR-safe for Norwegian public-sector deployments.
- Works offline / behind air-gapped firewalls.
- Forkers downloading the marketplace get a complete bundle.

All three families are SIL Open Font License 1.1 — license texts
included alongside the woff2 files. Source Serif 4 woff2 generated
locally from the upstream OTF release using
fonttools ttLib.woff2 compress; Inter and JetBrains Mono are
unmodified upstream webfont releases.

Total bundle: 9 woff2 files, ~940 KB. New fonts.css declares all
@font-face rules with font-display: swap. All 6 example HTMLs and 12
new component demos load it via a single relative path.

Verified
--------
- Privacy grep returns empty across plugins/ and shared/
- Google Fonts grep returns empty across shared/*.html
- Smoke test via python -m http.server: HTML + 7 stylesheets +
  Inter-Regular.woff2 all return 200

Doc updates
-----------
- shared/playground-design-system/README.md: file tree updated,
  Quick start snippet shows fonts.css link, "Self-hosted fonts"
  section added
- shared/playground-design-system/fonts/LICENSES.md: combined attribution
- README.md (root): Tier 3 wave 1+2 component list, Privacy-first bullet
- CLAUDE.md (root): tree entry expanded for new components + fonts

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-03 05:08:07 +02:00

462 lines
27 KiB
HTML
Raw Permalink 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="stylesheet" href="../playground-design-system/fonts.css" />
<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="stylesheet" href="../playground-design-system/fonts.css" /&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-direktorat.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-direktorat.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>