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>
This commit is contained in:
parent
5b6c1da8fc
commit
f1fecf39b8
36 changed files with 2470 additions and 29 deletions
|
|
@ -0,0 +1,100 @@
|
|||
<!doctype html>
|
||||
<html lang="nb">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Aspirational vs Committed · Tier 3 supp</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-supplement.css" />
|
||||
<link rel="stylesheet" href="../../playground-design-system/fonts.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header class="app-header">
|
||||
<a href="../index.html" class="app-header__brand"><span class="app-header__brand-mark">P</span><span>Playground</span></a>
|
||||
<span class="app-header__breadcrumb">/ Komponenter / Aspirational vs Committed</span>
|
||||
</header>
|
||||
|
||||
<main class="container container--default" style="padding: var(--space-8) 0;">
|
||||
<div style="margin-bottom: var(--space-6);">
|
||||
<span style="font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--color-scope-okr); font-weight: var(--font-weight-semibold);">OKR · visuell modus-skille</span>
|
||||
<h1 style="margin: 4px 0 6px;">Aspirational vs Committed</h1>
|
||||
<p class="text-secondary" style="max-width: 65ch;">Modifier på Objective-card. Aspirational (0,7 = success) har stiplet ring + ASP-badge. Committed (1,0 = expected) har solid ring + COM-badge.</p>
|
||||
</div>
|
||||
|
||||
<div style="display:grid; grid-template-columns: 1fr 1fr; gap: var(--space-4);">
|
||||
|
||||
<article class="okr-mode" data-mode="aspirational" title="Aspirasjon — 0,7 regnes som vellykket">
|
||||
<span class="okr-mode__badge">ASP</span>
|
||||
<div class="okr-mode__row">
|
||||
<div class="okr-mode__gauge">
|
||||
<svg viewBox="0 0 100 100" aria-hidden="true">
|
||||
<circle class="gauge-bg" cx="50" cy="50" r="42"></circle>
|
||||
<circle class="gauge-fill" cx="50" cy="50" r="42" stroke-dasharray="263.9" stroke-dashoffset="105.6"></circle>
|
||||
</svg>
|
||||
<span class="gauge-value">0,60</span>
|
||||
</div>
|
||||
<div>
|
||||
<div class="okr-mode__objective">Bli landets ledende kommune på AI-assistert saksbehandling innen 2027</div>
|
||||
<div class="okr-mode__hint">Aspirasjon — 0,7 regnes som vellykket</div>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="okr-mode" data-mode="committed" title="Committed — 1,0 forventes oppnådd">
|
||||
<span class="okr-mode__badge">COM</span>
|
||||
<div class="okr-mode__row">
|
||||
<div class="okr-mode__gauge">
|
||||
<svg viewBox="0 0 100 100" aria-hidden="true">
|
||||
<circle class="gauge-bg" cx="50" cy="50" r="42"></circle>
|
||||
<circle class="gauge-fill" cx="50" cy="50" r="42" stroke-dasharray="263.9" stroke-dashoffset="26.4"></circle>
|
||||
</svg>
|
||||
<span class="gauge-value">0,90</span>
|
||||
</div>
|
||||
<div>
|
||||
<div class="okr-mode__objective">Innfør sentralisert sensitivity-label-policy for alle 1 850 ansatte før 30. juni</div>
|
||||
<div class="okr-mode__hint">Committed — 1,0 forventes oppnådd</div>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="okr-mode" data-mode="aspirational">
|
||||
<span class="okr-mode__badge">ASP</span>
|
||||
<div class="okr-mode__row">
|
||||
<div class="okr-mode__gauge">
|
||||
<svg viewBox="0 0 100 100" aria-hidden="true">
|
||||
<circle class="gauge-bg" cx="50" cy="50" r="42"></circle>
|
||||
<circle class="gauge-fill" cx="50" cy="50" r="42" stroke-dasharray="263.9" stroke-dashoffset="184.7"></circle>
|
||||
</svg>
|
||||
<span class="gauge-value">0,30</span>
|
||||
</div>
|
||||
<div>
|
||||
<div class="okr-mode__objective">Halver gjennomsnittlig saksbehandlingstid på byggesøknader</div>
|
||||
<div class="okr-mode__hint">Aspirasjon — 0,3 så langt, fortsatt rom for å akselerere</div>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="okr-mode" data-mode="committed">
|
||||
<span class="okr-mode__badge">COM</span>
|
||||
<div class="okr-mode__row">
|
||||
<div class="okr-mode__gauge">
|
||||
<svg viewBox="0 0 100 100" aria-hidden="true">
|
||||
<circle class="gauge-bg" cx="50" cy="50" r="42"></circle>
|
||||
<circle class="gauge-fill" cx="50" cy="50" r="42" stroke-dasharray="263.9" stroke-dashoffset="0"></circle>
|
||||
</svg>
|
||||
<span class="gauge-value">1,00</span>
|
||||
</div>
|
||||
<div>
|
||||
<div class="okr-mode__objective">Levér T2-rapport til kommunestyret senest 5. september</div>
|
||||
<div class="okr-mode__hint">Committed — oppnådd</div>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
<!doctype html>
|
||||
<html lang="nb">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Classify & Transform · Tier 3 supp</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-supplement.css" />
|
||||
<link rel="stylesheet" href="../../playground-design-system/fonts.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header class="app-header">
|
||||
<a href="../index.html" class="app-header__brand"><span class="app-header__brand-mark">P</span><span>Playground</span></a>
|
||||
<span class="app-header__breadcrumb">/ Komponenter / Classify-and-Transform</span>
|
||||
</header>
|
||||
|
||||
<main class="container container--wide" style="padding: var(--space-8) 0;">
|
||||
<div style="margin-bottom: var(--space-6);">
|
||||
<span style="font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--color-scope-okr); font-weight: var(--font-weight-semibold);">OKR · /okr:skriv strategi-til-OKR</span>
|
||||
<h1 style="margin: 4px 0 6px;">5-bucket-sorter</h1>
|
||||
<p class="text-secondary" style="max-width: 65ch;">Lim inn tildelingsbrev øverst — hver krav-setning klassifiseres etter OKR-egnethet (lav, medium, høy).</p>
|
||||
</div>
|
||||
|
||||
<div class="cls-sorter">
|
||||
<div class="cls-input">
|
||||
<textarea id="inputText">Bærum kommune skal redusere ventetid på saksbehandling med 30 % innen utgangen av 2026. Innbyggerportalen skal være tilgjengelig 99,5 % av tiden. Andelen selvbetjente saker skal øke fra 42 % til 65 %. Vi skal modernisere innbyggerportalen med AI-assistert chat. Det skal leveres kvartalsrapport til kommunestyret om digitaliseringsfremgang. Copilot for saksbehandlere skal piloteres før Q3.</textarea>
|
||||
<div style="margin-top: var(--space-3); display: flex; gap: 8px;">
|
||||
<button class="btn btn--primary btn--sm" onclick="alert('Mock: 6 setninger klassifisert.')">Klassifiser</button>
|
||||
<span class="text-tertiary" style="font-size: 12px; align-self: center;">6 setninger funnet</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="cls-buckets" id="buckets"></div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
const buckets = {
|
||||
drift: { name: "Driftskrav", egnethet: "lav",
|
||||
items: [{text: "Sikre at innbyggerportalen er tilgjengelig 99,5 % av tiden", action: "→ KPI"}],
|
||||
cta: "Generer KPI-katalog" },
|
||||
resultat: { name: "Resultatmål", egnethet: "hoy",
|
||||
items: [
|
||||
{text: "Redusere ventetid på saksbehandling med 30 %", action: "→ KR-kandidat"},
|
||||
{text: "Øke andel selvbetjente saker fra 42 % til 65 %", action: "→ KR-kandidat"},
|
||||
],
|
||||
cta: "Generer KR-utkast" },
|
||||
satsing: { name: "Strategiske satsinger", egnethet: "hoy",
|
||||
items: [{text: "Modernisere innbyggerportalen med AI-assistert chat", action: "→ Objective-kandidat"}],
|
||||
cta: "Generer Objective-utkast" },
|
||||
rapportering: { name: "Rapportering", egnethet: "lav",
|
||||
items: [{text: "Kvartalsrapport til kommunestyret om digitaliseringsfremgang", action: "→ Rapporteringsrutine"}],
|
||||
cta: "Skriv rapportmal" },
|
||||
oppdrag: { name: "Særskilte oppdrag", egnethet: "medium",
|
||||
items: [{text: "Pilotere Copilot for saksbehandlere før Q3", action: "→ Case by case"}],
|
||||
cta: "Vurder OKR vs prosjekt" },
|
||||
};
|
||||
|
||||
function egnethetLabel(e) { return e === 'hoy' ? 'Høy egnethet' : e === 'medium' ? 'Medium egnethet' : 'Lav egnethet'; }
|
||||
|
||||
function render() {
|
||||
document.getElementById('buckets').innerHTML = Object.entries(buckets).map(([key, b]) => `
|
||||
<div class="cls-bucket" data-egnethet="${b.egnethet}" data-key="${key}">
|
||||
<div class="cls-bucket__head">
|
||||
<span class="cls-bucket__title">${b.name}</span>
|
||||
<span class="cls-bucket__egnethet">${egnethetLabel(b.egnethet)}</span>
|
||||
</div>
|
||||
${b.items.length ? b.items.map(i => `
|
||||
<div class="cls-item">
|
||||
<span>${i.text}</span>
|
||||
<span class="cls-item__action">${i.action}</span>
|
||||
</div>
|
||||
`).join('') : `<div class="cls-bucket__empty">Ingen setninger her.</div>`}
|
||||
<div class="cls-bucket__action">
|
||||
<button class="btn btn--secondary btn--sm" style="width:100%;" onclick="alert('Mock: ${b.cta}')">${b.cta}</button>
|
||||
</div>
|
||||
</div>
|
||||
`).join('');
|
||||
}
|
||||
render();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
90
shared/playground-examples/components/cycle-ribbon.html
Normal file
90
shared/playground-examples/components/cycle-ribbon.html
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
<!doctype html>
|
||||
<html lang="nb">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Cycle Position Ribbon · Tier 3 supp</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-supplement.css" />
|
||||
<link rel="stylesheet" href="../../playground-design-system/fonts.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header class="app-header">
|
||||
<a href="../index.html" class="app-header__brand"><span class="app-header__brand-mark">P</span><span>Playground</span></a>
|
||||
<span class="app-header__breadcrumb">/ Komponenter / Cycle Position Ribbon</span>
|
||||
</header>
|
||||
|
||||
<!-- Live ribbon (under header, mock T2-2026 uke 3 av 16) -->
|
||||
<button type="button" class="cycle-ribbon" data-phase="planning" aria-expanded="false" id="ribbon" style="--cycle-progress: 18%;" onclick="toggleRibbon()">
|
||||
<span class="cycle-ribbon__id">T2-2026</span>
|
||||
<span class="cycle-ribbon__week">Uke 3 / 16</span>
|
||||
<span class="cycle-ribbon__phase">Planning</span>
|
||||
<span class="cycle-ribbon__msg">Fokuser på check-in-rytme. Første team-check-in bør være innen uke 5.</span>
|
||||
<span class="cycle-ribbon__chev" aria-hidden="true">▾</span>
|
||||
</button>
|
||||
<div class="cycle-ribbon__panel" id="ribbonPanel">
|
||||
<div style="display:grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-4); align-items:start;">
|
||||
<div>
|
||||
<div class="text-tertiary" style="font-size: 11px; text-transform: uppercase; letter-spacing: .06em;">Periode</div>
|
||||
<strong>1. mai – 31. august 2026</strong>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-tertiary" style="font-size: 11px; text-transform: uppercase; letter-spacing: .06em;">Fase</div>
|
||||
<strong>Planning (uke 1–2)</strong>
|
||||
<div class="text-secondary" style="font-size: 12px;">Execution starter uke 3, retrospective_prep fra uke 14.</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-tertiary" style="font-size: 11px; text-transform: uppercase; letter-spacing: .06em;">Neste milepel</div>
|
||||
<strong>Team-check-in 1</strong>
|
||||
<div class="text-secondary" style="font-size: 12px;">Senest 24. mai 2026 (uke 5).</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<main class="container container--wide" style="padding: var(--space-8) 0;">
|
||||
<div style="margin-bottom: var(--space-6);">
|
||||
<span style="font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--color-scope-okr); font-weight: var(--font-weight-semibold);">OKR · persistent header</span>
|
||||
<h1 style="margin: 4px 0 6px;">Cycle Position Ribbon</h1>
|
||||
<p class="text-secondary" style="max-width: 65ch;">Persistent stripe under app-header som viser hvor i tertialen brukeren er. Klikk for detaljpanel.</p>
|
||||
</div>
|
||||
|
||||
<h2 style="font-size: var(--font-size-lg); margin: 0 0 var(--space-3);">Alle 3 faser</h2>
|
||||
|
||||
<div style="display:flex; flex-direction: column; gap: var(--space-4);">
|
||||
<div class="cycle-ribbon" data-phase="planning" style="--cycle-progress: 12%; border-radius: var(--radius-md); border: 1px solid var(--color-border-subtle);">
|
||||
<span class="cycle-ribbon__id">T2-2026</span>
|
||||
<span class="cycle-ribbon__week">Uke 2 / 16</span>
|
||||
<span class="cycle-ribbon__phase">Planning</span>
|
||||
<span class="cycle-ribbon__msg">Sett mål og forankre med ledelse.</span>
|
||||
<span class="cycle-ribbon__chev">▾</span>
|
||||
</div>
|
||||
<div class="cycle-ribbon" data-phase="execution" style="--cycle-progress: 50%; border-radius: var(--radius-md); border: 1px solid var(--color-border-subtle);">
|
||||
<span class="cycle-ribbon__id">T2-2026</span>
|
||||
<span class="cycle-ribbon__week">Uke 8 / 16</span>
|
||||
<span class="cycle-ribbon__phase">Execution</span>
|
||||
<span class="cycle-ribbon__msg">Halvveis. Halvveissamtale anbefales denne uka.</span>
|
||||
<span class="cycle-ribbon__chev">▾</span>
|
||||
</div>
|
||||
<div class="cycle-ribbon" data-phase="retrospective_prep" style="--cycle-progress: 88%; border-radius: var(--radius-md); border: 1px solid var(--color-border-subtle);">
|
||||
<span class="cycle-ribbon__id">T2-2026</span>
|
||||
<span class="cycle-ribbon__week">Uke 14 / 16</span>
|
||||
<span class="cycle-ribbon__phase">Retro-prep</span>
|
||||
<span class="cycle-ribbon__msg">Forbered scoring og retrospektiv. Frist for KR-scoring: 25. august.</span>
|
||||
<span class="cycle-ribbon__chev">▾</span>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
function toggleRibbon() {
|
||||
const r = document.getElementById('ribbon');
|
||||
const open = r.getAttribute('aria-expanded') === 'true';
|
||||
r.setAttribute('aria-expanded', open ? 'false' : 'true');
|
||||
document.getElementById('ribbonPanel').setAttribute('data-open', open ? 'false' : 'true');
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
85
shared/playground-examples/components/expansion-card.html
Normal file
85
shared/playground-examples/components/expansion-card.html
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
<!doctype html>
|
||||
<html lang="nb">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>ExpansionCard · Tier 3 supp</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-supplement.css" />
|
||||
<link rel="stylesheet" href="../../playground-design-system/fonts.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header class="app-header">
|
||||
<a href="../index.html" class="app-header__brand"><span class="app-header__brand-mark">P</span><span>Playground</span></a>
|
||||
<span class="app-header__breadcrumb">/ Komponenter / ExpansionCard</span>
|
||||
</header>
|
||||
|
||||
<main class="container container--default" style="padding: var(--space-8) 0;">
|
||||
<div style="margin-bottom: var(--space-6);">
|
||||
<span style="font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--color-text-tertiary); font-weight: var(--font-weight-semibold);">Aksel · progressive disclosure</span>
|
||||
<h1 style="margin: 4px 0 6px;">ExpansionCard</h1>
|
||||
<p class="text-secondary" style="max-width: 65ch;">Skjul sekundær informasjon bak klikkbar overskrift. Animert utvidelse respekterer prefers-reduced-motion.</p>
|
||||
</div>
|
||||
|
||||
<section class="expansion" aria-expanded="false">
|
||||
<button type="button" class="expansion__head" onclick="toggleExp(this)">
|
||||
<span class="expansion__title">
|
||||
<span class="expansion__title-main">Hva skjer hvis vi avviser denne ROS-rapporten?</span>
|
||||
<span class="expansion__title-sub">Konsekvenser for utrullingsplanen</span>
|
||||
</span>
|
||||
<span class="expansion__chev" aria-hidden="true">▾</span>
|
||||
</button>
|
||||
<div class="expansion__body"><div class="expansion__body-inner"><div>
|
||||
<p class="text-secondary" style="margin: 0 0 var(--space-2);">Avvises rapporten må arbeidsgruppen ta opp igjen tre trusler i kategori "Kritisk":</p>
|
||||
<ul style="font-size: var(--font-size-sm); color: var(--color-text-secondary); margin: 0 0 var(--space-2); padding-left: 20px;">
|
||||
<li>T-014 — DLP-policy for sensitivity labels</li>
|
||||
<li>T-022 — Cross-tenant Schrems II-vurdering</li>
|
||||
<li>T-031 — Audit-logging for prompt-historikk</li>
|
||||
</ul>
|
||||
<p class="text-secondary" style="margin: 0;">Forventet forsinkelse: 4–6 uker. Pilot-fasen flyttes fra juni til august.</p>
|
||||
</div></div></div>
|
||||
</section>
|
||||
|
||||
<section class="expansion" aria-expanded="false">
|
||||
<button type="button" class="expansion__head" onclick="toggleExp(this)">
|
||||
<span class="expansion__title">
|
||||
<span class="expansion__title-main">Hvilke roller skal signere?</span>
|
||||
<span class="expansion__title-sub">Sjekkliste før innsending</span>
|
||||
</span>
|
||||
<span class="expansion__chev" aria-hidden="true">▾</span>
|
||||
</button>
|
||||
<div class="expansion__body"><div class="expansion__body-inner"><div>
|
||||
<ul style="font-size: var(--font-size-sm); color: var(--color-text-secondary); margin: 0; padding-left: 20px;">
|
||||
<li>IT-sikkerhetsleder (Eli Bjerke)</li>
|
||||
<li>Personvernombud (Tor Vagle)</li>
|
||||
<li>Kommunaldirektør (sponsor)</li>
|
||||
<li>Tjenesteeier for berørt fagsystem</li>
|
||||
</ul>
|
||||
</div></div></div>
|
||||
</section>
|
||||
|
||||
<section class="expansion" aria-expanded="false">
|
||||
<button type="button" class="expansion__head" onclick="toggleExp(this)">
|
||||
<span class="expansion__title">
|
||||
<span class="expansion__title-main">Tekniske detaljer for sentralisert konfig</span>
|
||||
</span>
|
||||
<span class="expansion__chev" aria-hidden="true">▾</span>
|
||||
</button>
|
||||
<div class="expansion__body"><div class="expansion__body-inner"><div>
|
||||
<p class="text-secondary" style="margin: 0;">Konfig versjoneres i <code>git.fromaitochitta.com/playground/configs</code>, valideres ved CI mot <code>config.schema.json</code>, og distribueres via signert artifact til target-tenants.</p>
|
||||
</div></div></div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
function toggleExp(btn) {
|
||||
const sec = btn.parentElement;
|
||||
const open = sec.getAttribute('aria-expanded') === 'true';
|
||||
sec.setAttribute('aria-expanded', open ? 'false' : 'true');
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
102
shared/playground-examples/components/fleet-overview.html
Normal file
102
shared/playground-examples/components/fleet-overview.html
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
<!doctype html>
|
||||
<html lang="nb">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Fleet-Overview · Tier 3 supp</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-supplement.css" />
|
||||
<link rel="stylesheet" href="../../playground-design-system/fonts.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header class="app-header">
|
||||
<a href="../index.html" class="app-header__brand"><span class="app-header__brand-mark">P</span><span>Playground</span></a>
|
||||
<span class="app-header__breadcrumb">/ Komponenter / Fleet-Overview</span>
|
||||
</header>
|
||||
|
||||
<main class="container container--wide" style="padding: var(--space-8) 0;">
|
||||
<div style="margin-bottom: var(--space-6);">
|
||||
<span style="font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--color-scope-security); font-weight: var(--font-weight-semibold);">llm-security · /security dashboard</span>
|
||||
<h1 style="margin: 4px 0 6px;">Fleet-Overview</h1>
|
||||
<p class="text-secondary" style="max-width: 65ch;">Cross-project posture på én skjerm. 4 kolonner desktop → 2 → 1.</p>
|
||||
</div>
|
||||
|
||||
<div class="fleet-toolbar">
|
||||
<span class="fleet-toolbar__label">Sortér</span>
|
||||
<button class="chip" aria-pressed="true" onclick="sortFleet('worst')">Verste først</button>
|
||||
<button class="chip" aria-pressed="false" onclick="sortFleet('alpha')">Alfabetisk</button>
|
||||
<button class="chip" aria-pressed="false" onclick="sortFleet('recent')">Sist skannet</button>
|
||||
<span class="fleet-toolbar__label" style="margin-left: var(--space-4);">Filter</span>
|
||||
<button class="chip" aria-pressed="false" onclick="filterFleet('failing')">Kun F + E</button>
|
||||
<button class="chip" aria-pressed="false" onclick="filterFleet('changed')">Kun med endringer</button>
|
||||
<span class="fleet-toolbar__spacer"></span>
|
||||
<span class="fleet-toolbar__count" id="fleetCount">12 prosjekter</span>
|
||||
</div>
|
||||
|
||||
<div class="fleet-grid" id="fleetGrid"></div>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
const projects = [
|
||||
{ name: "lier-kommune/copilot-onboarding", grade: "A", risk: 12, band: 1, worst: "info-disclosure", scanned: "2026-05-02 14:11", trend: "stable", changed: false },
|
||||
{ name: "baerum-kommune/okr-portal", grade: "B", risk: 28, band: 1, worst: "missing-rate-limit", scanned: "2026-05-02 09:32", trend: "better", changed: true },
|
||||
{ name: "direktorat/sak-arkiv-mcp", grade: "C", risk: 44, band: 2, worst: "weak-auth", scanned: "2026-05-01 18:04", trend: "worse", changed: true },
|
||||
{ name: "direktorat/llm-saksbehandler", grade: "F", risk: 87, band: 4, worst: "TFA chain (BLOCK)", scanned: "2026-05-02 02:55", trend: "worse", changed: true },
|
||||
{ name: "trondheim/dpia-helper", grade: "B", risk: 22, band: 1, worst: "log-leakage", scanned: "2026-04-30 11:18", trend: "stable", changed: false },
|
||||
{ name: "skatteetaten/intern-kb", grade: "D", risk: 61, band: 3, worst: "prompt-injection", scanned: "2026-05-02 07:42", trend: "better", changed: true },
|
||||
{ name: "nav/saksbehandler-co", grade: "C", risk: 39, band: 2, worst: "ssrf-risk", scanned: "2026-05-01 23:01", trend: "stable", changed: false },
|
||||
{ name: "udi/ai-translator", grade: "E", risk: 73, band: 3, worst: "data-residency", scanned: "2026-05-02 12:30", trend: "worse", changed: true },
|
||||
{ name: "dsb/krise-bot", grade: "A", risk: 8, band: 1, worst: "minor-typo", scanned: "2026-04-29 16:50", trend: "stable", changed: false },
|
||||
{ name: "domstol/dom-summary", grade: "B", risk: 25, band: 1, worst: "context-leakage", scanned: "2026-05-01 10:14", trend: "better", changed: true },
|
||||
{ name: "helsedir/symptomsjekk", grade: "F", risk: 91, band: 4, worst: "PHI exfiltration", scanned: "2026-05-02 04:18", trend: "worse", changed: true },
|
||||
{ name: "kommune/innsyn-mcp", grade: "C", risk: 47, band: 2, worst: "broad-scope", scanned: "2026-05-01 19:55", trend: "stable", changed: false },
|
||||
];
|
||||
|
||||
const trendArrow = { better: "↗ bedre", worse: "↘ verre", stable: "→ stabil" };
|
||||
const grid = document.getElementById('fleetGrid');
|
||||
let mode = 'worst', filter = 'none';
|
||||
|
||||
function render() {
|
||||
let list = projects.slice();
|
||||
if (filter === 'failing') list = list.filter(p => p.grade === 'F' || p.grade === 'E');
|
||||
if (filter === 'changed') list = list.filter(p => p.changed);
|
||||
if (mode === 'worst') list.sort((a,b) => b.risk - a.risk);
|
||||
if (mode === 'alpha') list.sort((a,b) => a.name.localeCompare(b.name));
|
||||
if (mode === 'recent') list.sort((a,b) => b.scanned.localeCompare(a.scanned));
|
||||
grid.innerHTML = list.map(p => `
|
||||
<button class="fleet-tile" onclick="alert('Naviger til posture for ${p.name}')">
|
||||
<div class="fleet-tile__row">
|
||||
<span class="fleet-tile__name" title="${p.name}">${p.name}</span>
|
||||
<span class="fleet-tile__grade" data-grade="${p.grade}">${p.grade}</span>
|
||||
</div>
|
||||
<div class="fleet-tile__meter"><div class="fleet-tile__meter-fill" data-band="${p.band}" style="width:${p.risk}%"></div></div>
|
||||
<span class="fleet-tile__chip">${p.worst}</span>
|
||||
<div class="fleet-tile__meta">
|
||||
<span>${p.scanned}</span>
|
||||
<span class="fleet-tile__trend--${p.trend}">${trendArrow[p.trend]}</span>
|
||||
</div>
|
||||
</button>
|
||||
`).join('');
|
||||
document.getElementById('fleetCount').textContent = list.length + ' prosjekter';
|
||||
}
|
||||
|
||||
function sortFleet(m) {
|
||||
mode = m;
|
||||
document.querySelectorAll('.fleet-toolbar .chip').forEach(c => {
|
||||
if (['Verste først', 'Alfabetisk', 'Sist skannet'].includes(c.textContent)) c.setAttribute('aria-pressed', 'false');
|
||||
});
|
||||
event.target.setAttribute('aria-pressed', 'true');
|
||||
render();
|
||||
}
|
||||
function filterFleet(f) {
|
||||
filter = filter === f ? 'none' : f;
|
||||
event.target.setAttribute('aria-pressed', filter === f ? 'true' : 'false');
|
||||
render();
|
||||
}
|
||||
render();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
81
shared/playground-examples/components/form-progress.html
Normal file
81
shared/playground-examples/components/form-progress.html
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
<!doctype html>
|
||||
<html lang="nb">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>FormProgress · Tier 3 supp</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-supplement.css" />
|
||||
<link rel="stylesheet" href="../../playground-design-system/fonts.css" />
|
||||
<style>
|
||||
.demo-layout { display: grid; grid-template-columns: 280px 1fr; gap: var(--space-6); align-items: start; }
|
||||
@media (max-width: 820px) { .demo-layout { grid-template-columns: 1fr; } .form-progress { width: 100%; position: static; } }
|
||||
.form-area { background: var(--color-surface); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-md); padding: var(--space-5); min-height: 360px; }
|
||||
</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</span></a>
|
||||
<span class="app-header__breadcrumb">/ Komponenter / FormProgress</span>
|
||||
</header>
|
||||
|
||||
<main class="container container--wide" style="padding: var(--space-8) 0;">
|
||||
<div style="margin-bottom: var(--space-6);">
|
||||
<span style="font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--color-scope-architect); font-weight: var(--font-weight-semibold);">ms-ai-architect onboarding · OKR /oppsett full · DPIA</span>
|
||||
<h1 style="margin: 4px 0 6px;">FormProgress</h1>
|
||||
<p class="text-secondary" style="max-width: 65ch;">Vertikal sidebar for store skjema. Autosave-status, ferdig-prosent per steg, estimert resterende tid. Ikke å forveksle med horisontal stepper.</p>
|
||||
</div>
|
||||
|
||||
<div class="demo-layout">
|
||||
<aside class="form-progress">
|
||||
<div class="form-progress__autosave">
|
||||
<span class="form-progress__autosave-dot" aria-hidden="true"></span>
|
||||
Lagret automatisk kl. 14:23
|
||||
</div>
|
||||
<div class="form-progress__steps">
|
||||
<button type="button" class="fp-step" data-state="done">
|
||||
<span class="fp-step__num">✓</span>
|
||||
<span><span class="fp-step__name">Organisasjon & kontekst</span></span>
|
||||
</button>
|
||||
<button type="button" class="fp-step" data-state="done">
|
||||
<span class="fp-step__num">✓</span>
|
||||
<span><span class="fp-step__name">Brukstilfeller</span></span>
|
||||
</button>
|
||||
<button type="button" class="fp-step" data-state="in-progress">
|
||||
<span class="fp-step__num">3</span>
|
||||
<span>
|
||||
<span class="fp-step__name">Datakilder & klassifisering</span>
|
||||
<span class="fp-step__progress">
|
||||
<span>62 %</span>
|
||||
<span class="fp-step__bar"><span class="fp-step__bar-fill" style="width:62%"></span></span>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button type="button" class="fp-step" data-state="todo" disabled title="Fullfør steg 3 først">
|
||||
<span class="fp-step__num">4</span>
|
||||
<span><span class="fp-step__name">Roller & ansvar</span></span>
|
||||
</button>
|
||||
<button type="button" class="fp-step" data-state="todo" disabled title="Fullfør steg 3 først">
|
||||
<span class="fp-step__num">5</span>
|
||||
<span><span class="fp-step__name">Risiko & tiltak</span></span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="form-progress__remaining">
|
||||
<span>Resterende</span>
|
||||
<span>~ 9 min</span>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<section class="form-area">
|
||||
<div class="text-tertiary" style="font-size: 11px; text-transform: uppercase; letter-spacing: .06em;">Steg 3 av 5</div>
|
||||
<h2 style="margin: 4px 0 var(--space-4); font-size: var(--font-size-xl);">Datakilder & klassifisering</h2>
|
||||
<p class="text-secondary" style="font-size: var(--font-size-sm);">Skjemaet hadde 12 felt — 7 utfylt, 5 igjen. Estimert ferdig om 5 minutter.</p>
|
||||
<div style="margin-top: var(--space-4); padding: var(--space-4); background: var(--color-bg-soft); border-radius: var(--radius-md); font-size: var(--font-size-sm); color: var(--color-text-tertiary);">[Skjema-felt placeholder — i produksjon: input/select/textarea]</div>
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
144
shared/playground-examples/components/kanban.html
Normal file
144
shared/playground-examples/components/kanban.html
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
<!doctype html>
|
||||
<html lang="nb">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Kanban · Keep/Review/Remove · Tier 3 supp</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-supplement.css" />
|
||||
<link rel="stylesheet" href="../../playground-design-system/fonts.css" />
|
||||
<style>
|
||||
.modal-bg { position: fixed; inset: 0; background: var(--color-overlay); display: none; align-items: center; justify-content: center; z-index: 100; padding: var(--space-4); }
|
||||
.modal-bg[data-open="true"] { display: flex; }
|
||||
.modal { background: var(--color-surface); border-radius: var(--radius-lg); padding: var(--space-5); max-width: 540px; width: 100%; box-shadow: var(--shadow-lg); max-height: 90vh; overflow: auto; }
|
||||
.checklist { list-style: none; padding: 0; margin: var(--space-3) 0; display: flex; flex-direction: column; gap: 6px; }
|
||||
.checklist li { display: flex; gap: 8px; font-size: var(--font-size-sm); }
|
||||
.checklist .ok { color: var(--color-state-success); }
|
||||
.checklist .no { color: var(--color-severity-critical); }
|
||||
.checklist .un { color: var(--color-text-tertiary); }
|
||||
</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</span></a>
|
||||
<span class="app-header__breadcrumb">/ Komponenter / Kanban: Keep/Review/Remove</span>
|
||||
</header>
|
||||
|
||||
<main class="container container--wide" style="padding: var(--space-8) 0;">
|
||||
<div style="margin-bottom: var(--space-6);">
|
||||
<span style="font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--color-scope-security); font-weight: var(--font-weight-semibold);">llm-security · /security plugin-audit</span>
|
||||
<h1 style="margin: 4px 0 6px;">Kanban: Behold / Vurder / Fjern</h1>
|
||||
<p class="text-secondary" style="max-width: 65ch;">Klassifisér installerte plugins/MCP-servere etter trust. Klikk-flytt mellom kolonner.</p>
|
||||
</div>
|
||||
|
||||
<div class="kanban-board" id="board"></div>
|
||||
</main>
|
||||
|
||||
<div class="modal-bg" id="modal" onclick="if(event.target===this) closeModal()">
|
||||
<div class="modal" id="modalBody"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const board = {
|
||||
keep: { title: "Behold", items: [
|
||||
{ name: "anthropic/claude-code-mcp", verdict: "trusted", meta: "Sist auditert 2026-04-15" },
|
||||
{ name: "github/copilot-chat", verdict: "trusted", meta: "Sist auditert 2026-04-12" },
|
||||
{ name: "lier-kommune/internal-mcp", verdict: "trusted", meta: "Sist auditert 2026-04-30" },
|
||||
{ name: "digdir/auth-mcp", verdict: "trusted", meta: "Sist auditert 2026-05-01" },
|
||||
]},
|
||||
review: { title: "Vurder", items: [
|
||||
{ name: "thirdparty/web-search", verdict: "unknown", meta: "Audit due 2026-06-01" },
|
||||
{ name: "community/markdown-tools", verdict: "unknown", meta: "Audit due 2026-05-20" },
|
||||
]},
|
||||
remove: { title: "Fjern", items: [
|
||||
{ name: "evil-project-health@1.2.3", verdict: "BLOCK", reason: "85 funn (24 critical), Unicode-steganografi, exfil-flow" },
|
||||
]},
|
||||
};
|
||||
|
||||
const checklists = {
|
||||
trusted: [
|
||||
{ok:'ok', text:'Source repo verifisert (signed commits)'},
|
||||
{ok:'ok', text:'Maintainer kjent og aktiv'},
|
||||
{ok:'ok', text:'Ingen kritiske funn siste audit'},
|
||||
{ok:'ok', text:'Capabilities dokumentert og minst-mulig'},
|
||||
{ok:'ok', text:'Ingen exfil-flow detektert'},
|
||||
{ok:'ok', text:'Lisens kompatibel med offentlig bruk'},
|
||||
{ok:'ok', text:'Versjon pinnet i lockfile'},
|
||||
{ok:'ok', text:'Endringslogg konsistent med kode'},
|
||||
{ok:'ok', text:'Trust-skår > 80'},
|
||||
],
|
||||
unknown: [
|
||||
{ok:'un', text:'Source repo verifisert'},
|
||||
{ok:'ok', text:'Maintainer kjent'},
|
||||
{ok:'un', text:'Audit ikke utført siste 90 d'},
|
||||
{ok:'ok', text:'Capabilities dokumentert'},
|
||||
{ok:'un', text:'Exfil-analyse ikke kjørt'},
|
||||
{ok:'ok', text:'Lisens OK'},
|
||||
{ok:'ok', text:'Versjon pinnet'},
|
||||
{ok:'un', text:'Endringslogg ufullstendig'},
|
||||
{ok:'un', text:'Trust-skår ikke beregnet'},
|
||||
],
|
||||
BLOCK: [
|
||||
{ok:'no', text:'Unicode-tag-injeksjon i README (steganografi)'},
|
||||
{ok:'no', text:'Exfil til webhook.site/abc123 detektert'},
|
||||
{ok:'no', text:'24 kritiske TFA-funn'},
|
||||
{ok:'no', text:'Maintainer ikke verifiserbar'},
|
||||
{ok:'no', text:'Source-repo nylig opprettet (typosquat?)'},
|
||||
{ok:'no', text:'Bash + filsystem + nett uten begrensning'},
|
||||
{ok:'no', text:'Lisens uklar'},
|
||||
{ok:'no', text:'Versjon ikke pinnet'},
|
||||
{ok:'no', text:'Trust-skår: 4'},
|
||||
],
|
||||
};
|
||||
|
||||
function render() {
|
||||
document.getElementById('board').innerHTML = ['keep','review','remove'].map(b => `
|
||||
<div class="kanban-col" data-bucket="${b}">
|
||||
<div class="kanban-col__head">
|
||||
<span class="kanban-col__title">${board[b].title}</span>
|
||||
<span class="kanban-col__count">${board[b].items.length}</span>
|
||||
</div>
|
||||
${board[b].items.length ? board[b].items.map((it, i) => `
|
||||
<div class="kanban-card" data-verdict="${it.verdict}" onclick="openModal('${b}', ${i})">
|
||||
<span class="kanban-card__name">${it.name}</span>
|
||||
${it.meta ? `<span class="kanban-card__meta">${it.meta}</span>` : ''}
|
||||
${it.reason ? `<span class="kanban-card__reason">${it.reason}</span>` : ''}
|
||||
<div class="kanban-actions" onclick="event.stopPropagation()">
|
||||
${b !== 'keep' ? `<button onclick="move('${b}','keep',${i})">→ Behold</button>` : ''}
|
||||
${b !== 'review' ? `<button onclick="move('${b}','review',${i})">→ Vurder</button>` : ''}
|
||||
${b !== 'remove' ? `<button onclick="move('${b}','remove',${i})">→ Fjern</button>` : ''}
|
||||
</div>
|
||||
</div>
|
||||
`).join('') : `<div class="kanban-col__empty">Ingen i denne bøtten ennå.<br><button class="btn btn--secondary btn--sm" style="margin-top:8px;">+ Legg til</button></div>`}
|
||||
</div>
|
||||
`).join('');
|
||||
}
|
||||
|
||||
function move(from, to, i) {
|
||||
const item = board[from].items.splice(i, 1)[0];
|
||||
board[to].items.push(item);
|
||||
render();
|
||||
}
|
||||
|
||||
function openModal(b, i) {
|
||||
const it = board[b].items[i];
|
||||
const cl = checklists[it.verdict] || checklists.unknown;
|
||||
const sym = { ok: '✓', no: '✗', un: '?' };
|
||||
document.getElementById('modalBody').innerHTML = `
|
||||
<div style="display:flex; justify-content:space-between; align-items:center; gap:12px;">
|
||||
<h3 style="margin:0;">${it.name}</h3>
|
||||
<button class="btn btn--ghost btn--sm" onclick="closeModal()">Lukk</button>
|
||||
</div>
|
||||
<p class="text-secondary" style="font-size:var(--font-size-sm); margin:6px 0 0;">Trust-vurdering · ${it.verdict.toUpperCase()}</p>
|
||||
<ul class="checklist">${cl.map(c => `<li><span class="${c.ok}">${sym[c.ok]}</span><span>${c.text}</span></li>`).join('')}</ul>
|
||||
`;
|
||||
document.getElementById('modal').setAttribute('data-open', 'true');
|
||||
}
|
||||
function closeModal() { document.getElementById('modal').setAttribute('data-open', 'false'); }
|
||||
render();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
97
shared/playground-examples/components/maturity-ladder.html
Normal file
97
shared/playground-examples/components/maturity-ladder.html
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
<!doctype html>
|
||||
<html lang="nb">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Maturity-Ladder · Tier 3 supp</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-supplement.css" />
|
||||
<link rel="stylesheet" href="../../playground-design-system/fonts.css" />
|
||||
<style>
|
||||
.demo-row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-5); }
|
||||
@media (max-width: 980px) { .demo-row { grid-template-columns: 1fr; } }
|
||||
</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</span></a>
|
||||
<span class="app-header__breadcrumb">/ Komponenter / Maturity-Ladder</span>
|
||||
</header>
|
||||
|
||||
<main class="container container--wide" style="padding: var(--space-8) 0;">
|
||||
<div style="margin-bottom: var(--space-6);">
|
||||
<span style="font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--color-scope-okr); font-weight: var(--font-weight-semibold);">OKR · config-audit · security</span>
|
||||
<h1 style="margin: 4px 0 6px;">Maturity-Ladder</h1>
|
||||
<p class="text-secondary" style="max-width: 65ch;">Vertikal stepper med rik beskrivelse. Current step har progress-ring (her 65 %).</p>
|
||||
</div>
|
||||
|
||||
<div class="demo-row">
|
||||
<section>
|
||||
<h2 style="font-size: var(--font-size-lg); margin: 0 0 var(--space-3);">OKR-modenhet (4 nivåer)</h2>
|
||||
<div class="mat-ladder">
|
||||
<div class="mat-step" data-state="completed">
|
||||
<div class="mat-step__icon" aria-hidden="true">✓</div>
|
||||
<div>
|
||||
<div class="mat-step__name">Utforsker <span class="mat-step__pill mat-step__pill--complete">Fullført</span></div>
|
||||
<div class="mat-step__desc">Eksperimenterer med OKR i 1–2 team. Ingen formell rytme.</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mat-step" data-state="current">
|
||||
<div class="mat-step__icon" aria-hidden="true">
|
||||
2
|
||||
<span class="mat-step__ring" aria-hidden="true">
|
||||
<svg viewBox="0 0 52 52"><circle class="ring-bg" cx="26" cy="26" r="24"></circle><circle class="ring-fill" cx="26" cy="26" r="24" stroke-dasharray="150.8" stroke-dashoffset="52.8"></circle></svg>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<div class="mat-step__name">Pilot <span class="mat-step__pill mat-step__pill--current">Nå</span></div>
|
||||
<div class="mat-step__desc">OKR i én avdeling. Kvartalsrytme etablert. Ledelse engasjert.</div>
|
||||
<div class="mat-step__progress"><span>65 %</span><span class="mat-step__progress-bar"><span class="mat-step__progress-fill" style="width:65%"></span></span><span>til Skalering</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mat-step" data-state="future">
|
||||
<div class="mat-step__icon" aria-hidden="true">3</div>
|
||||
<div>
|
||||
<div class="mat-step__name">Skalering</div>
|
||||
<div class="mat-step__desc">OKR rullet ut til hele organisasjonen. Cross-team alignment.</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mat-step" data-state="future">
|
||||
<div class="mat-step__icon" aria-hidden="true">4</div>
|
||||
<div>
|
||||
<div class="mat-step__name">Moden</div>
|
||||
<div class="mat-step__desc">OKR er drift. Strategisk forankring fra Stortingsmelding til team-OKR.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2 style="font-size: var(--font-size-lg); margin: 0 0 var(--space-3);">Config-modenhet (5 nivåer)</h2>
|
||||
<div class="mat-ladder">
|
||||
<div class="mat-step" data-state="completed"><div class="mat-step__icon" aria-hidden="true">✓</div>
|
||||
<div><div class="mat-step__name">Bare <span class="mat-step__pill mat-step__pill--complete">Fullført</span></div>
|
||||
<div class="mat-step__desc">Defaults overalt. Ingen sentralisert konfig.</div></div></div>
|
||||
<div class="mat-step" data-state="completed"><div class="mat-step__icon" aria-hidden="true">✓</div>
|
||||
<div><div class="mat-step__name">Configured <span class="mat-step__pill mat-step__pill--complete">Fullført</span></div>
|
||||
<div class="mat-step__desc">Eksplisitte verdier per miljø. Ingen drift-deteksjon.</div></div></div>
|
||||
<div class="mat-step" data-state="current"><div class="mat-step__icon" aria-hidden="true">3
|
||||
<span class="mat-step__ring" aria-hidden="true"><svg viewBox="0 0 52 52"><circle class="ring-bg" cx="26" cy="26" r="24"></circle><circle class="ring-fill" cx="26" cy="26" r="24" stroke-dasharray="150.8" stroke-dashoffset="105.6"></circle></svg></span></div>
|
||||
<div><div class="mat-step__name">Structured <span class="mat-step__pill mat-step__pill--current">Nå</span></div>
|
||||
<div class="mat-step__desc">Skjema-validert konfig. Versjonert i Git. Endringssporbarhet.</div>
|
||||
<div class="mat-step__progress"><span>30 %</span><span class="mat-step__progress-bar"><span class="mat-step__progress-fill" style="width:30%"></span></span><span>til Automated</span></div></div></div>
|
||||
<div class="mat-step" data-state="future"><div class="mat-step__icon" aria-hidden="true">4</div>
|
||||
<div><div class="mat-step__name">Automated</div>
|
||||
<div class="mat-step__desc">CI-validering. Auto-rollback ved feil. Drift-detektor.</div></div></div>
|
||||
<div class="mat-step" data-state="future"><div class="mat-step__icon" aria-hidden="true">5</div>
|
||||
<div><div class="mat-step__name">Governed</div>
|
||||
<div class="mat-step__desc">Policy-as-code. Audit-trail. Approval-workflows for prod.</div></div></div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
<!doctype html>
|
||||
<html lang="nb">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Persistent-Antipattern Badge · Tier 3 supp</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-supplement.css" />
|
||||
<link rel="stylesheet" href="../../playground-design-system/fonts.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header class="app-header">
|
||||
<a href="../index.html" class="app-header__brand"><span class="app-header__brand-mark">P</span><span>Playground</span></a>
|
||||
<span class="app-header__breadcrumb">/ Komponenter / Persistent-Antipattern Badge</span>
|
||||
</header>
|
||||
|
||||
<main class="container container--wide" style="padding: var(--space-8) 0;">
|
||||
<div style="margin-bottom: var(--space-6);">
|
||||
<span style="font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--color-scope-okr); font-weight: var(--font-weight-semibold);">OKR · /okr:analyse cross-cycle</span>
|
||||
<h1 style="margin: 4px 0 6px;">Persistent-Antipattern Badge</h1>
|
||||
<p class="text-secondary" style="max-width: 65ch;">Markerer antipatterns som har dukket opp i 2+ påfølgende sykluser. Pulserende prikk skiller seg fra one-shot.</p>
|
||||
</div>
|
||||
|
||||
<h2 style="font-size: var(--font-size-lg); margin: 0 0 var(--space-3);">I bruk i en finding-tabell</h2>
|
||||
<table style="width:100%; border-collapse: collapse; background: var(--color-surface); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-md); overflow:hidden;">
|
||||
<thead>
|
||||
<tr style="background: var(--color-bg-soft);">
|
||||
<th style="text-align:left; padding: 10px 14px; font-size: 12px; text-transform: uppercase; letter-spacing: .06em; color: var(--color-text-tertiary); border-bottom: 1px solid var(--color-border-subtle);">Antipattern</th>
|
||||
<th style="text-align:left; padding: 10px 14px; font-size: 12px; text-transform: uppercase; letter-spacing: .06em; color: var(--color-text-tertiary); border-bottom: 1px solid var(--color-border-subtle);">Funnet i</th>
|
||||
<th style="text-align:left; padding: 10px 14px; font-size: 12px; text-transform: uppercase; letter-spacing: .06em; color: var(--color-text-tertiary); border-bottom: 1px solid var(--color-border-subtle);">Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="padding: 12px 14px;">Aktivitetsfokus i KR</td>
|
||||
<td style="padding: 12px 14px; font-family: var(--font-family-mono); font-size: 12px; color: var(--color-text-secondary);">T1-25 · T2-25 · T3-25 · T1-26 · T2-26</td>
|
||||
<td style="padding: 12px 14px;">
|
||||
<button type="button" class="pap-badge" onclick="togglePap(0)" aria-expanded="false" aria-controls="papDetail0">
|
||||
Vedvarende <span class="pap-badge__count">5 sykluser</span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 12px 14px;">Sandbagging av target-verdier</td>
|
||||
<td style="padding: 12px 14px; font-family: var(--font-family-mono); font-size: 12px; color: var(--color-text-secondary);">T2-25 · T3-25 · T1-26</td>
|
||||
<td style="padding: 12px 14px;">
|
||||
<button type="button" class="pap-badge" onclick="togglePap(1)" aria-expanded="false" aria-controls="papDetail1">
|
||||
Vedvarende <span class="pap-badge__count">3 sykluser</span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 12px 14px;">For mange KR per Objective</td>
|
||||
<td style="padding: 12px 14px; font-family: var(--font-family-mono); font-size: 12px; color: var(--color-text-secondary);">T2-26</td>
|
||||
<td style="padding: 12px 14px;">
|
||||
<span class="pap-badge pap-badge--oneshot" title="Kun én syklus så langt">Én syklus</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<section class="pap-detail" id="papDetail0" style="margin-top: var(--space-3);">
|
||||
<h4>Aktivitetsfokus i KR</h4>
|
||||
<p class="text-secondary" style="margin: 0; font-size: var(--font-size-sm);">KR-formuleringer beskriver aktiviteter ("Innføre nytt system", "Pilotere X") i stedet for målbare utfall. Vedvarende mønster på tvers av sykluser indikerer at OKR-coaching ikke har festet seg.</p>
|
||||
<div class="pap-detail__cycles">
|
||||
<span class="pap-detail__cycle">T1-2025 · 4 forekomster</span>
|
||||
<span class="pap-detail__cycle">T2-2025 · 3 forekomster</span>
|
||||
<span class="pap-detail__cycle">T3-2025 · 5 forekomster</span>
|
||||
<span class="pap-detail__cycle">T1-2026 · 6 forekomster</span>
|
||||
<span class="pap-detail__cycle">T2-2026 · 4 forekomster</span>
|
||||
</div>
|
||||
<div class="pap-detail__rec"><strong>Anbefaling:</strong> Vurder OKR-coaching eller retrospective-fokus på outcome vs activity. Spør "Hva endrer seg for innbyggeren hvis dette KR-et oppfylles?"</div>
|
||||
</section>
|
||||
|
||||
<section class="pap-detail" id="papDetail1" style="margin-top: var(--space-3);">
|
||||
<h4>Sandbagging av target-verdier</h4>
|
||||
<p class="text-secondary" style="margin: 0; font-size: var(--font-size-sm);">Targets satt så lavt at de oppnås uten reell innsats. Score > 0,9 to sykluser på rad uten endring i baseline.</p>
|
||||
<div class="pap-detail__cycles">
|
||||
<span class="pap-detail__cycle">T2-2025</span>
|
||||
<span class="pap-detail__cycle">T3-2025</span>
|
||||
<span class="pap-detail__cycle">T1-2026</span>
|
||||
</div>
|
||||
<div class="pap-detail__rec"><strong>Anbefaling:</strong> Innfør stretch-target som komplement, eller vurder aspirational vs committed-skille (se OKR-mode).</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
function togglePap(i) {
|
||||
const d = document.getElementById('papDetail' + i);
|
||||
const open = d.getAttribute('data-open') === 'true';
|
||||
d.setAttribute('data-open', open ? 'false' : 'true');
|
||||
event.currentTarget.setAttribute('aria-expanded', open ? 'false' : 'true');
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
59
shared/playground-examples/components/read-more.html
Normal file
59
shared/playground-examples/components/read-more.html
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
<!doctype html>
|
||||
<html lang="nb">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>ReadMore · Tier 3 supp</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-supplement.css" />
|
||||
<link rel="stylesheet" href="../../playground-design-system/fonts.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header class="app-header">
|
||||
<a href="../index.html" class="app-header__brand"><span class="app-header__brand-mark">P</span><span>Playground</span></a>
|
||||
<span class="app-header__breadcrumb">/ Komponenter / ReadMore</span>
|
||||
</header>
|
||||
|
||||
<main class="container container--narrow" style="padding: var(--space-8) 0;">
|
||||
<div style="margin-bottom: var(--space-6);">
|
||||
<span style="font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--color-text-tertiary); font-weight: var(--font-weight-semibold);">Aksel · inline disclosure</span>
|
||||
<h1 style="margin: 4px 0 6px;">ReadMore</h1>
|
||||
<p class="text-secondary">Inline-trigger for å skjule lange forklaringer mid-tekst.</p>
|
||||
</div>
|
||||
|
||||
<article style="font-size: var(--font-size-md); line-height: var(--line-height-normal); color: var(--color-text-primary);">
|
||||
<p>Sensitivity Labels brukes til å klassifisere dokumenter etter konfidensialitetsnivå.
|
||||
<span class="read-more" aria-expanded="false">
|
||||
<button type="button" class="read-more__trigger" onclick="toggleRm(this)">Les mer om hvordan dette håndheves <span class="read-more__chev">▾</span></button>
|
||||
<span class="read-more__body">
|
||||
Når et dokument merkes "Konfidensielt — intern", vil M365 Copilot ikke oppsummere innholdet for brukere uten samme tilgangsnivå.
|
||||
DLP-policyen sjekker label-attributter ved hver prompt-respons og avbryter generering hvis cross-label data flyter sammen.
|
||||
For Lier kommune betyr dette at saksbehandlere på Helse-avdelingen ikke utilsiktet kan dra inn HR-relatert informasjon i samme svar.
|
||||
</span>
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<p style="margin-top: var(--space-4);">Schrems II-vurdering kreves for cross-tenant data-flyt.
|
||||
<span class="read-more" aria-expanded="false">
|
||||
<button type="button" class="read-more__trigger" onclick="toggleRm(this)">Hva betyr Schrems II i praksis? <span class="read-more__chev">▾</span></button>
|
||||
<span class="read-more__body">
|
||||
EU-domstolen kjente Privacy Shield ugyldig i 2020. Overføring av personopplysninger til USA krever supplerende tiltak (TIAs, krypteringsnøkler i EU).
|
||||
For Microsoft 365-tenants betyr dette at EU Data Boundary må være aktivert, og at audit-logger må bekrefte at prompt-data ikke forlater EØS.
|
||||
</span>
|
||||
</span>
|
||||
</p>
|
||||
</article>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
function toggleRm(btn) {
|
||||
const sec = btn.parentElement;
|
||||
const open = sec.getAttribute('aria-expanded') === 'true';
|
||||
sec.setAttribute('aria-expanded', open ? 'false' : 'true');
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
117
shared/playground-examples/components/sankey-toxic-flow.html
Normal file
117
shared/playground-examples/components/sankey-toxic-flow.html
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
<!doctype html>
|
||||
<html lang="nb">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Toxic-Flow Chain · Tier 3 supp</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-supplement.css" />
|
||||
<link rel="stylesheet" href="../../playground-design-system/fonts.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header class="app-header">
|
||||
<a href="../index.html" class="app-header__brand"><span class="app-header__brand-mark">P</span><span>Playground</span></a>
|
||||
<span class="app-header__breadcrumb">/ Komponenter / Toxic-Flow Chain (TFA)</span>
|
||||
</header>
|
||||
|
||||
<main class="container container--wide" style="padding: var(--space-8) 0;">
|
||||
<div style="margin-bottom: var(--space-6);">
|
||||
<span style="font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--color-scope-security); font-weight: var(--font-weight-semibold);">llm-security · TFA</span>
|
||||
<h1 style="margin: 4px 0 6px;">Toxic-Flow Chain</h1>
|
||||
<p class="text-secondary" style="max-width: 65ch;">Trifecta Flow Analysis: Input → Access → Exfil. Hver leg viser type, kilde og mitigation-status. Tykkere arrows = høyere severity. Grønt skjold = mitigation som bryter kjeden.</p>
|
||||
</div>
|
||||
|
||||
<h2 style="font-size: var(--font-size-lg); margin: 0 0 var(--space-3);">TFA-2026-118-001 — BLOCK</h2>
|
||||
<div class="tfa-flow" id="flow1">
|
||||
<span class="tfa-flow__verdict" data-verdict="BLOCK">BLOCK</span>
|
||||
|
||||
<button type="button" class="tfa-leg" data-severity="high" onclick="alert('Drill-down: Input leg — skill markdown fil')">
|
||||
<span class="tfa-leg__label">Input</span>
|
||||
<span class="tfa-leg__name">Untrusted data</span>
|
||||
<span class="tfa-leg__source">skill markdown-fil</span>
|
||||
<span class="tfa-leg__status" data-mit="unmitigated">● Ikke mitigert</span>
|
||||
</button>
|
||||
|
||||
<span class="tfa-arrow" data-severity="critical" aria-hidden="true"><span class="tfa-arrow__line"></span></span>
|
||||
|
||||
<button type="button" class="tfa-leg" data-severity="critical" onclick="alert('Drill-down: Access leg — Bash + filsystem')">
|
||||
<span class="tfa-leg__label">Access</span>
|
||||
<span class="tfa-leg__name">Sensitive capability</span>
|
||||
<span class="tfa-leg__source">Bash · filsystem-tilgang</span>
|
||||
<span class="tfa-leg__status" data-mit="partially_mitigated">◐ Delvis mitigert</span>
|
||||
</button>
|
||||
|
||||
<span class="tfa-arrow" data-severity="critical" aria-hidden="true"><span class="tfa-arrow__line"></span></span>
|
||||
|
||||
<button type="button" class="tfa-leg" data-severity="critical" onclick="alert('Drill-down: Exfil leg — webhook.site')">
|
||||
<span class="tfa-leg__label">Exfil</span>
|
||||
<span class="tfa-leg__name">External endpoint</span>
|
||||
<span class="tfa-leg__source">webhook.site/abc123</span>
|
||||
<span class="tfa-leg__status" data-mit="unmitigated">● Ikke mitigert</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<h2 style="font-size: var(--font-size-lg); margin: var(--space-8) 0 var(--space-3);">TFA-2026-118-002 — WARN (mitigation present)</h2>
|
||||
<div class="tfa-flow">
|
||||
<span class="tfa-flow__verdict" data-verdict="WARN">WARN</span>
|
||||
<button type="button" class="tfa-leg" data-severity="medium">
|
||||
<span class="tfa-leg__label">Input</span>
|
||||
<span class="tfa-leg__name">User prompt</span>
|
||||
<span class="tfa-leg__source">chat input</span>
|
||||
<span class="tfa-leg__status" data-mit="mitigated">✓ Sanert</span>
|
||||
</button>
|
||||
<span class="tfa-arrow tfa-arrow--mitigated" data-severity="medium" aria-hidden="true">
|
||||
<span class="tfa-arrow__line"></span>
|
||||
<span class="tfa-arrow__shield" title="Sanitering bryter kjeden">🛡</span>
|
||||
</span>
|
||||
<button type="button" class="tfa-leg" data-severity="high">
|
||||
<span class="tfa-leg__label">Access</span>
|
||||
<span class="tfa-leg__name">Read-only DB query</span>
|
||||
<span class="tfa-leg__source">SELECT-only role</span>
|
||||
<span class="tfa-leg__status" data-mit="partially_mitigated">◐ RBAC aktiv</span>
|
||||
</button>
|
||||
<span class="tfa-arrow" data-severity="high" aria-hidden="true"><span class="tfa-arrow__line"></span></span>
|
||||
<button type="button" class="tfa-leg" data-severity="high">
|
||||
<span class="tfa-leg__label">Exfil</span>
|
||||
<span class="tfa-leg__name">Logged endpoint</span>
|
||||
<span class="tfa-leg__source">api.bærum.no/log</span>
|
||||
<span class="tfa-leg__status" data-mit="mitigated">✓ Audit-sporet</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<h2 style="font-size: var(--font-size-lg); margin: var(--space-8) 0 var(--space-3);">TFA-2026-118-003 — ALLOW</h2>
|
||||
<div class="tfa-flow">
|
||||
<span class="tfa-flow__verdict" data-verdict="ALLOW">ALLOW</span>
|
||||
<button type="button" class="tfa-leg" data-severity="medium">
|
||||
<span class="tfa-leg__label">Input</span>
|
||||
<span class="tfa-leg__name">Konfig-fil</span>
|
||||
<span class="tfa-leg__source">checked-in config.toml</span>
|
||||
<span class="tfa-leg__status" data-mit="mitigated">✓ Signert</span>
|
||||
</button>
|
||||
<span class="tfa-arrow tfa-arrow--mitigated" data-severity="medium" aria-hidden="true">
|
||||
<span class="tfa-arrow__line"></span>
|
||||
<span class="tfa-arrow__shield">🛡</span>
|
||||
</span>
|
||||
<button type="button" class="tfa-leg" data-severity="medium">
|
||||
<span class="tfa-leg__label">Access</span>
|
||||
<span class="tfa-leg__name">Local file read</span>
|
||||
<span class="tfa-leg__source">repo-scope</span>
|
||||
<span class="tfa-leg__status" data-mit="mitigated">✓ Sandboxed</span>
|
||||
</button>
|
||||
<span class="tfa-arrow tfa-arrow--mitigated" data-severity="medium" aria-hidden="true">
|
||||
<span class="tfa-arrow__line"></span>
|
||||
<span class="tfa-arrow__shield">🛡</span>
|
||||
</span>
|
||||
<button type="button" class="tfa-leg" data-severity="medium">
|
||||
<span class="tfa-leg__label">Exfil</span>
|
||||
<span class="tfa-leg__name">Stdout</span>
|
||||
<span class="tfa-leg__source">terminal</span>
|
||||
<span class="tfa-leg__status" data-mit="mitigated">✓ Lokalt</span>
|
||||
</button>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
<!doctype html>
|
||||
<html lang="nb">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Suppressed-Signals · Tier 3 supp</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-supplement.css" />
|
||||
<link rel="stylesheet" href="../../playground-design-system/fonts.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header class="app-header">
|
||||
<a href="../index.html" class="app-header__brand"><span class="app-header__brand-mark">P</span><span>Playground</span></a>
|
||||
<span class="app-header__breadcrumb">/ Komponenter / Suppressed-Signals Panel</span>
|
||||
</header>
|
||||
|
||||
<main class="container container--wide" style="padding: var(--space-8) 0;">
|
||||
<div style="margin-bottom: var(--space-6);">
|
||||
<span style="font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--color-scope-security); font-weight: var(--font-weight-semibold);">llm-security · ultraplan-local</span>
|
||||
<h1 style="margin: 4px 0 6px;">Suppressed-Signals Panel</h1>
|
||||
<p class="text-secondary" style="max-width: 65ch;">Synlig — men sammenklappet — liste over funn som ble nedgradert eller fjernet, og hvorfor. Aldri skjult i en meny: tillit krever transparens.</p>
|
||||
</div>
|
||||
|
||||
<p class="text-tertiary" style="font-size: var(--font-size-sm); margin: 0 0 8px;">Etter funn-listen, før footer:</p>
|
||||
|
||||
<section class="suppressed" aria-expanded="false" id="sup">
|
||||
<button type="button" class="suppressed__head" onclick="toggleSup()">
|
||||
<span class="suppressed__chev" aria-hidden="true">▸</span>
|
||||
<span class="suppressed__label">12 signaler ble dempet eller fjernet i denne kjøringen</span>
|
||||
<span class="suppressed__count">12</span>
|
||||
</button>
|
||||
<div class="suppressed__body">
|
||||
<div class="suppressed-group">
|
||||
<div class="suppressed-group__head">
|
||||
<span class="suppressed-group__reason">false_positive_glsl_keywords</span>
|
||||
<span class="suppressed-group__count">8 funn</span>
|
||||
</div>
|
||||
<p class="suppressed-group__desc">Entropy-scanner flagget GLSL shader-keywords som secrets. Nedgradert til info etter regel-treff på <code>shaders/*.glsl</code>.</p>
|
||||
<div class="suppressed-group__examples">
|
||||
<span class="suppressed-group__example">uniform vec3</span>
|
||||
<span class="suppressed-group__example">varying mat4</span>
|
||||
<span class="suppressed-group__example">gl_FragCoord</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="suppressed-group">
|
||||
<div class="suppressed-group__head">
|
||||
<span class="suppressed-group__reason">test_fixture_intended</span>
|
||||
<span class="suppressed-group__count">3 funn</span>
|
||||
</div>
|
||||
<p class="suppressed-group__desc">Fixture-filer i <code>tests/fixtures/</code> med bevisst dummy-data (bestått manuell review 2026-04-22).</p>
|
||||
</div>
|
||||
<div class="suppressed-group">
|
||||
<div class="suppressed-group__head">
|
||||
<span class="suppressed-group__reason">judge_succinctness_filter</span>
|
||||
<span class="suppressed-group__count">1 funn</span>
|
||||
</div>
|
||||
<p class="suppressed-group__desc">Findings under 4 ord — ikke handlebar. Filtrert ut av Judge.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
function toggleSup() {
|
||||
const s = document.getElementById('sup');
|
||||
const open = s.getAttribute('aria-expanded') === 'true';
|
||||
s.setAttribute('aria-expanded', open ? 'false' : 'true');
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Add table
Add a link
Reference in a new issue