diff --git a/CLAUDE.md b/CLAUDE.md index ba7185c..a14d093 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -17,8 +17,8 @@ plugins/ ultra-cc-architect/ v0.1.0 — Claude-Code-specific architecture matching + skill-factory (extracted from ultraplan-local in v3.0.0) shared/ - playground-design-system/ v0.1 — Aksel/Digdir-aligned CSS design system + JSON schemas for plugin Playgrounds (consumed by ms-ai-architect, okr, llm-security, ultraplan-local, config-audit) - playground-examples/ — Reference scenarios (ROS-Lier, OKR-Bærum, security-Direktorat) + showcase landing + playground-design-system/ v0.1 — Aksel/Digdir-aligned CSS design system + JSON schemas + self-hosted Inter/JetBrains Mono/Source Serif 4 fonts (Tier 1+2+3 wave 1+wave 2 = 20 Tier 3 components total). Consumed by ms-ai-architect, okr, llm-security, ultraplan-local, config-audit + playground-examples/ — Reference scenarios (ROS-Lier, OKR-Bærum, security-Direktorat) + showcase landing + 12 isolated Tier 3 wave 2 component demos under components/ ``` Hvert plugin er selvstendig med egen CLAUDE.md, README, hooks, agents og commands. `shared/` inneholder marketplace-nivå infrastruktur som flere plugins bygger på. diff --git a/README.md b/README.md index 92b510d..03af5e7 100644 --- a/README.md +++ b/README.md @@ -247,10 +247,12 @@ Shared design system for plugin Playgrounds — visual self-service UIs that com Targets five plugins: `ms-ai-architect`, `okr`, `llm-security`, `ultraplan-local`, `config-audit`. Built for Norwegian public sector decision-makers (kommunaldirektører, sikkerhetsoffiserer, OKR-koordinatorer) plus developer power-users — one visual family, two information densities. -- **Tokens** — Inter font, body 17px, Digdir blue `#0062BA`, deuteranopia-safe severity ramp, distinct severity-red vs failure-red, plugin-scope colors, semantic CSS custom properties +- **Tokens** — Inter/JetBrains Mono/Source Serif 4 (all self-hosted, OFL 1.1), body 17px, Digdir blue `#0062BA`, deuteranopia-safe severity ramp, distinct severity-red vs failure-red, plugin-scope colors, semantic CSS custom properties - **Tier 1 components** — radar/spider, 5×5 matrix-heatmap (bottom-left origin, ROS/DPIA), findings-browser, critique-card, wizard/stepper, live-meter with antipattern lints - **Tier 2 components** — decision-tree (AI Act 4-step), traffic-lights, diff-review, treemap (token hotspots), distribution P10/P50/P90, command-pipeline output, AI Act 4-color pyramide, pipeline-cockpit, verdict-pill + 5-band risk-meter, codepoint-reveal (Unicode steganography), small-multiples grid (16-category posture without overcrowded radar), OWASP badges (LLM/ASI/AST/MCP) +- **Tier 3 components (wave 1+2, 20 total)** — pair-before-after, AI Act timeline, 3-track entry, FRIA rights-matrix, capability-matrix, parallel-agent-status, ErrorSummary, GuidePanel, 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 - **JSON schemas** — `finding.schema.json`, `okr-set.schema.json`, `ros-threat.schema.json` for cross-plugin data interchange +- **Privacy-first** — all fonts self-hosted as woff2 in `fonts/`, zero external CDN requests, GDPR-safe for offentlig sektor, works offline / behind air-gapped firewalls - **Reference scenarios** — Lier kommune ROS-rapport (ms-ai-architect), Bærum kommune T2 OKR live-writer, Direktoratet for digital tjenesteutvikling ToxicSkills findings review (85 funn, BLOCK) → [Full documentation](shared/playground-design-system/README.md) · [Browse showcase](shared/playground-examples/index.html) diff --git a/shared/playground-design-system/README.md b/shared/playground-design-system/README.md index fd404f7..b54de64 100644 --- a/shared/playground-design-system/README.md +++ b/shared/playground-design-system/README.md @@ -20,7 +20,14 @@ shared/ │ ├── base.css # Reset, typography, primitives, focus, print │ ├── components.css # Tier 1: radar, matrix, findings-browser, critique-card, wizard, live-meter │ ├── components-tier2.css # Tier 2: decision-tree, traffic-lights, diff-review, treemap, distribution, command-pipeline, pyramide, pipeline-cockpit, verdict-pill+risk-meter, codepoint-reveal, small-multiples, OWASP badges -│ ├── components-tier3.css # Tier 3: pair-before-after, AI Act timeline, 3-track entry, FRIA rights-matrix, capability-matrix, parallel-agent-status, ErrorSummary, GuidePanel +│ ├── components-tier3.css # Tier 3 wave 1: pair-before-after, AI Act timeline, 3-track entry, FRIA rights-matrix, capability-matrix, parallel-agent-status, ErrorSummary, GuidePanel +│ ├── components-tier3-supplement.css # Tier 3 wave 2 (12): toxic-flow, fleet-overview, kanban Keep/Review/Remove, maturity-ladder, classify-and-transform, cycle-ribbon, persistent-antipattern, suppressed-signals, ExpansionCard, ReadMore, FormProgress, Aspirational-vs-Committed +│ ├── fonts.css # @font-face declarations for self-hosted fonts +│ ├── fonts/ # Self-hosted woff2 + license attribution +│ │ ├── Inter-{Regular,Medium,SemiBold,Bold}.woff2 +│ │ ├── JetBrainsMono-{Regular,Medium,SemiBold}.woff2 +│ │ ├── SourceSerif4-{Regular,Semibold}.woff2 +│ │ └── LICENSES.md # All three are SIL OFL 1.1 │ ├── print.css # A4 print stylesheet with B/W severity patterns │ └── schemas/ # Cross-plugin JSON schemas │ ├── finding.schema.json # Used by llm-security, config-audit, ultraplan-review, ms-ai-review @@ -31,8 +38,22 @@ shared/ ├── index.html # System showcase (browse all components) ├── ros-lier-kommune.html # Scenario A — ms-ai-architect ROS report ├── okr-baerum.html # Scenario B — OKR live writer - ├── security-direktorat.html # Scenario C — llm-security findings review + ├── security-direktorat.html # Scenario C — llm-security findings review ├── templates.html # Skeleton + print-template demos + ├── tier3-preview.html # Tier 3 wave 1 visual preview + ├── components/ # Tier 3 wave 2 — 12 isolated demo pages + │ ├── sankey-toxic-flow.html + │ ├── fleet-overview.html + │ ├── kanban.html + │ ├── maturity-ladder.html + │ ├── classify-transform.html + │ ├── cycle-ribbon.html + │ ├── persistent-antipattern.html + │ ├── suppressed-signals.html + │ ├── expansion-card.html + │ ├── read-more.html + │ ├── form-progress.html + │ └── aspirational-committed.html ├── ros-app.js # Scenario A interactivity └── ros-data.js # Scenario A mock data ``` @@ -50,8 +71,12 @@ To use the design system from a plugin's Playground: + + + +
@@ -166,13 +191,15 @@ localStorage.setItem('theme', document.documentElement.dataset.theme); Include `print.css` if your scenario produces an A4 report. Then add `class="no-print"` to interactive chrome (header, buttons, theme toggle), and use `class="page-break"` to force page breaks. Severity-coded matrix cells will automatically render as B/W-safe hatching patterns when printed. The `.print-header` and `.print-footer` blocks support kommune-logo slots and signature lines for offentlige dokumenter. -## Known limitations (Phase 1) +## Known limitations -1. **Google Fonts CDN dependency.** All example HTML files load Inter from `fonts.googleapis.com`. This violates the "self-contained, no CDN" constraint. The system-font-stack fallback in `base.css` works, so files render acceptably offline — but for production deployment, Inter should be self-hosted as woff2 files in `playground-design-system/fonts/`. Tracked for Phase 2. -2. **Tier 3 components missing.** Several components from the design brief are not yet implemented: rights-matrix (FRIA 12 EU Charter), capability-matrix (license × kapabilitet), fleet-overview (cross-project security dashboard), kanban (Keep/Review/Remove), sankey/toxic-flow chain (security TFA), classify-and-transform (OKR 5-bucket sorter), maturity-ladder (OKR/posture progression), parallel-agent-status panel (utredning, ultraexecute waves), suppressed-signals panel. -3. **No JavaScript framework.** Components are CSS-first. Interactivity (e.g. `aria-selected` toggling, sidepanel open/close, live-meter updates) must be wired by each Playground using vanilla JS. See `playground-examples/ros-app.js` for a reference implementation pattern. -4. **No icon set bundled.** The system assumes Lucide or Phosphor SVG sprites are inlined per Playground. Iconography is intentionally out-of-system to keep the shared system small. -5. **Mobile responsiveness is partial.** The 5×5 matrix, findings-browser, codepoint-reveal split-pane, and small-multiples grid have explicit `@media (max-width: ...)` rules. Other components may need polish for narrow viewports. +1. **No JavaScript framework.** Components are CSS-first. Interactivity (e.g. `aria-selected` toggling, sidepanel open/close, live-meter updates) must be wired by each Playground using vanilla JS. See `playground-examples/ros-app.js` for a reference implementation pattern. +2. **No icon set bundled.** The system assumes Lucide or Phosphor SVG sprites are inlined per Playground. Iconography is intentionally out-of-system to keep the shared system small. +3. **Mobile responsiveness is partial.** The 5×5 matrix, findings-browser, codepoint-reveal split-pane, and small-multiples grid have explicit `@media (max-width: ...)` rules. Other components may need polish for narrow viewports. + +## Self-hosted fonts + +All three font families (Inter, JetBrains Mono, Source Serif 4) are bundled as woff2 in `fonts/` and loaded via `fonts.css`. No external requests to Google Fonts or any CDN. All three are SIL OFL 1.1 — see `fonts/LICENSES.md` for full attribution. ## Versioning diff --git a/shared/playground-design-system/components-tier3-supplement.css b/shared/playground-design-system/components-tier3-supplement.css new file mode 100644 index 0000000..cfdf9fc --- /dev/null +++ b/shared/playground-design-system/components-tier3-supplement.css @@ -0,0 +1,886 @@ +/* ============================================================================= + components-tier3-supplement.css + Tier 3 supplement — 12 components added after Tier 3 main set. + Pinned rules: + - No big pink fills for text. Use surface bg + colored border + dark body text. + - severity-critical (#A40E26) ≠ state-failed (#7D1A1A). Don't conflate. + - Light + dark theme via existing tokens only. + ============================================================================= */ + +/* ========================================================================= + 1. Sankey / Toxic-Flow Chain (.tfa-flow) + 3-step: Input → Access → Exfil with mitigation shields breaking the chain. + ========================================================================= */ +.tfa-flow { + display: grid; + grid-template-columns: 1fr auto 1fr auto 1fr; + gap: 0; + align-items: stretch; + background: var(--color-surface); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-lg); + padding: var(--space-5); + position: relative; +} +.tfa-flow__verdict { + position: absolute; + top: -12px; right: var(--space-5); + padding: 4px 10px; + font-size: 11px; + font-weight: var(--font-weight-bold); + letter-spacing: 0.06em; + border-radius: var(--radius-pill); + background: var(--color-severity-critical); + color: #fff; +} +.tfa-flow__verdict[data-verdict="ALLOW"] { background: var(--color-state-success); } +.tfa-flow__verdict[data-verdict="WARN"] { background: var(--color-severity-medium); color: #fff; } +.tfa-flow__verdict[data-verdict="BLOCK"] { background: var(--color-severity-critical); } + +.tfa-leg { + display: flex; flex-direction: column; gap: 6px; + padding: var(--space-3); + background: var(--color-surface); + border: 1px solid var(--color-border-subtle); + border-left-width: 4px; + border-radius: var(--radius-md); + cursor: pointer; + transition: background var(--duration-fast) var(--ease-default); + text-align: left; +} +.tfa-leg:hover { background: var(--color-bg-soft); } +.tfa-leg:focus-visible { outline: none; box-shadow: var(--shadow-focus); } +.tfa-leg[data-severity="medium"] { border-left-color: var(--color-severity-medium); } +.tfa-leg[data-severity="high"] { border-left-color: var(--color-severity-high); } +.tfa-leg[data-severity="critical"] { border-left-color: var(--color-severity-critical); } + +.tfa-leg__label { + font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; + color: var(--color-text-tertiary); font-weight: var(--font-weight-semibold); +} +.tfa-leg__name { font-size: var(--font-size-md); font-weight: var(--font-weight-semibold); color: var(--color-text-primary); } +.tfa-leg__source { font-family: var(--font-family-mono); font-size: 12px; color: var(--color-text-secondary); } +.tfa-leg__status { + margin-top: auto; + font-size: 11px; + font-weight: var(--font-weight-medium); + display: inline-flex; align-items: center; gap: 4px; +} +.tfa-leg__status[data-mit="unmitigated"] { color: var(--color-severity-critical); } +.tfa-leg__status[data-mit="partially_mitigated"] { color: var(--color-severity-medium); } +.tfa-leg__status[data-mit="mitigated"] { color: var(--color-state-success); } + +/* Arrow connectors. Width grows with severity */ +.tfa-arrow { + display: flex; align-items: center; justify-content: center; + position: relative; + min-width: 56px; + padding: 0 4px; +} +.tfa-arrow__line { + height: 4px; + width: 100%; + background: var(--color-border-moderate); + position: relative; +} +.tfa-arrow[data-severity="medium"] .tfa-arrow__line { background: var(--color-severity-medium); height: 6px; } +.tfa-arrow[data-severity="high"] .tfa-arrow__line { background: var(--color-severity-high); height: 8px; } +.tfa-arrow[data-severity="critical"] .tfa-arrow__line { background: var(--color-severity-critical); height: 10px; } +.tfa-arrow__line::after { + content: ""; position: absolute; right: -1px; top: 50%; + width: 0; height: 0; + border-left: 10px solid currentColor; + border-top: 8px solid transparent; + border-bottom: 8px solid transparent; + transform: translateY(-50%); + color: inherit; +} +.tfa-arrow[data-severity="medium"] .tfa-arrow__line { color: var(--color-severity-medium); } +.tfa-arrow[data-severity="high"] .tfa-arrow__line { color: var(--color-severity-high); } +.tfa-arrow[data-severity="critical"] .tfa-arrow__line { color: var(--color-severity-critical); } + +.tfa-arrow__shield { + position: absolute; + top: 50%; left: 50%; + transform: translate(-50%, -50%); + width: 32px; height: 32px; + background: var(--color-state-success); + color: #fff; + border-radius: 50%; + display: flex; align-items: center; justify-content: center; + border: 3px solid var(--color-surface); + font-size: 16px; +} +.tfa-arrow--mitigated .tfa-arrow__line { + background: repeating-linear-gradient(90deg, var(--color-state-success) 0 4px, transparent 4px 8px); +} + +@media (max-width: 720px) { + .tfa-flow { + grid-template-columns: 1fr; + grid-template-rows: auto auto auto auto auto; + } + .tfa-arrow { min-height: 48px; min-width: auto; } + .tfa-arrow__line { width: 4px; height: 100%; } + .tfa-arrow[data-severity="medium"] .tfa-arrow__line { width: 6px; height: 100%; } + .tfa-arrow[data-severity="high"] .tfa-arrow__line { width: 8px; height: 100%; } + .tfa-arrow[data-severity="critical"] .tfa-arrow__line { width: 10px; height: 100%; } + .tfa-arrow__line::after { + right: 50%; top: auto; bottom: -1px; transform: translateX(50%); + border-left: 8px solid transparent; + border-right: 8px solid transparent; + border-top: 10px solid currentColor; + border-bottom: none; + } +} + +/* ========================================================================= + 2. Fleet-Overview (.fleet-grid, .fleet-tile) + ========================================================================= */ +.fleet-toolbar { + display: flex; gap: var(--space-3); flex-wrap: wrap; + align-items: center; + padding: var(--space-3) var(--space-4); + background: var(--color-bg-soft); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-md); + margin-bottom: var(--space-3); +} +.fleet-toolbar__label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--color-text-tertiary); font-weight: var(--font-weight-semibold); } +.fleet-toolbar__spacer { flex: 1; } +.fleet-toolbar__count { font-size: var(--font-size-sm); color: var(--color-text-secondary); } + +.fleet-grid { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: var(--space-3); +} +@media (max-width: 980px) { .fleet-grid { grid-template-columns: repeat(2, 1fr); } } +@media (max-width: 540px) { .fleet-grid { grid-template-columns: 1fr; } } + +.fleet-tile { + background: var(--color-surface); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-md); + padding: var(--space-3); + display: grid; + grid-template-rows: auto auto auto auto; + gap: 6px; + cursor: pointer; + transition: border-color var(--duration-fast), transform var(--duration-fast); +} +.fleet-tile:hover { border-color: var(--color-primary-300); transform: translateY(-1px); } +.fleet-tile:focus-visible { outline: none; box-shadow: var(--shadow-focus); } + +.fleet-tile__row { display: flex; justify-content: space-between; align-items: center; gap: 8px; } +.fleet-tile__name { + font-family: var(--font-family-mono); + font-size: 12px; + color: var(--color-text-primary); + white-space: nowrap; overflow: hidden; text-overflow: ellipsis; + flex: 1; +} +.fleet-tile__grade { + width: 28px; height: 28px; + display: flex; align-items: center; justify-content: center; + font-weight: var(--font-weight-bold); + font-size: 13px; + border-radius: var(--radius-sm); + color: #fff; + flex-shrink: 0; +} +.fleet-tile__grade[data-grade="A"] { background: var(--color-state-success); } +.fleet-tile__grade[data-grade="B"] { background: #4D8E2F; } +.fleet-tile__grade[data-grade="C"] { background: var(--color-severity-medium); } +.fleet-tile__grade[data-grade="D"] { background: var(--color-severity-high); } +.fleet-tile__grade[data-grade="E"] { background: var(--color-severity-critical); } +.fleet-tile__grade[data-grade="F"] { background: var(--color-severity-extreme); } + +.fleet-tile__meter { + height: 6px; border-radius: 3px; + background: var(--color-bg-soft); + overflow: hidden; + position: relative; +} +.fleet-tile__meter-fill { height: 100%; border-radius: 3px; } +.fleet-tile__meter-fill[data-band="1"] { background: var(--color-state-success); } +.fleet-tile__meter-fill[data-band="2"] { background: var(--color-severity-medium); } +.fleet-tile__meter-fill[data-band="3"] { background: var(--color-severity-high); } +.fleet-tile__meter-fill[data-band="4"] { background: var(--color-severity-critical); } + +.fleet-tile__chip { + display: inline-flex; align-items: center; + font-size: 11px; + padding: 2px 8px; + border-radius: var(--radius-pill); + background: var(--color-bg-soft); + color: var(--color-text-secondary); + border: 1px solid var(--color-border-subtle); + width: fit-content; +} +.fleet-tile__meta { + display: flex; justify-content: space-between; + font-size: 11px; color: var(--color-text-tertiary); + font-family: var(--font-family-mono); +} +.fleet-tile__trend--better { color: var(--color-state-success); } +.fleet-tile__trend--worse { color: var(--color-severity-critical); } +.fleet-tile__trend--stable { color: var(--color-text-tertiary); } + +/* ========================================================================= + 3. Kanban Keep / Review / Remove (.kanban-board) + ========================================================================= */ +.kanban-board { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: var(--space-4); +} +@media (max-width: 820px) { .kanban-board { grid-template-columns: 1fr; } } + +.kanban-col { + background: var(--color-bg-soft); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-md); + padding: var(--space-3); + display: flex; flex-direction: column; gap: var(--space-3); + min-height: 320px; +} +.kanban-col__head { + display: flex; align-items: center; justify-content: space-between; + padding-bottom: var(--space-2); + border-bottom: 2px solid var(--color-border-subtle); +} +.kanban-col[data-bucket="keep"] .kanban-col__head { border-bottom-color: var(--color-state-success); } +.kanban-col[data-bucket="review"] .kanban-col__head { border-bottom-color: var(--color-state-warning); } +.kanban-col[data-bucket="remove"] .kanban-col__head { border-bottom-color: var(--color-severity-critical); } + +.kanban-col__title { font-size: var(--font-size-md); font-weight: var(--font-weight-semibold); color: var(--color-text-primary); } +.kanban-col__count { + font-family: var(--font-family-mono); + font-size: 12px; + background: var(--color-surface); + padding: 2px 8px; + border-radius: var(--radius-pill); + color: var(--color-text-secondary); + border: 1px solid var(--color-border-subtle); +} + +.kanban-card { + background: var(--color-surface); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-md); + padding: var(--space-3); + cursor: grab; + display: flex; flex-direction: column; gap: 6px; + transition: box-shadow var(--duration-fast); +} +.kanban-card:hover { box-shadow: var(--shadow-md); } +.kanban-card[data-verdict="BLOCK"] { border-color: var(--color-severity-critical); border-left-width: 4px; } +.kanban-card[data-verdict="trusted"] { border-left: 4px solid var(--color-state-success); } +.kanban-card[data-verdict="unknown"] { border-left: 4px solid var(--color-state-warning); } + +.kanban-card__name { font-family: var(--font-family-mono); font-size: 13px; color: var(--color-text-primary); word-break: break-all; } +.kanban-card__meta { font-size: 11px; color: var(--color-text-tertiary); } +.kanban-card__reason { font-size: 12px; color: var(--color-text-secondary); } + +.kanban-col__empty { + margin: auto; + text-align: center; + color: var(--color-text-tertiary); + font-size: var(--font-size-sm); + padding: var(--space-4); +} +.kanban-col__empty button { margin-top: var(--space-2); } + +.kanban-actions { display: flex; gap: 4px; margin-top: 4px; } +.kanban-actions button { + flex: 1; font-size: 11px; padding: 4px 6px; + background: var(--color-bg-soft); border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-sm); color: var(--color-text-secondary); + cursor: pointer; font-family: inherit; +} +.kanban-actions button:hover { background: var(--color-surface-sunken); color: var(--color-text-primary); } + +/* ========================================================================= + 4. Maturity-Ladder (.mat-ladder) + ========================================================================= */ +.mat-ladder { + display: flex; flex-direction: column; + background: var(--color-surface); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-md); + padding: var(--space-4); + gap: 0; +} +.mat-step { + display: grid; + grid-template-columns: 56px 1fr; + gap: var(--space-4); + padding: var(--space-3) 0; + position: relative; +} +.mat-step + .mat-step { border-top: 1px dashed var(--color-border-subtle); } + +.mat-step__icon { + width: 44px; height: 44px; + border-radius: 50%; + display: flex; align-items: center; justify-content: center; + background: var(--color-surface); + border: 2px solid var(--color-border-moderate); + color: var(--color-text-tertiary); + font-weight: var(--font-weight-semibold); + font-size: 15px; + position: relative; + z-index: 1; +} +.mat-step[data-state="completed"] .mat-step__icon { + background: var(--color-state-success); + border-color: var(--color-state-success); + color: #fff; +} +.mat-step[data-state="current"] .mat-step__icon { + border-color: var(--color-primary-500); + color: var(--color-primary-700); + background: var(--color-surface); +} + +/* progress ring around current step */ +.mat-step__ring { + position: absolute; + inset: -4px; + border-radius: 50%; + pointer-events: none; +} +.mat-step__ring svg { width: 100%; height: 100%; transform: rotate(-90deg); } +.mat-step__ring circle { fill: none; stroke-width: 3; } +.mat-step__ring .ring-bg { stroke: var(--color-border-subtle); } +.mat-step__ring .ring-fill { stroke: var(--color-primary-500); } + +.mat-step__name { + font-size: var(--font-size-md); + font-weight: var(--font-weight-semibold); + color: var(--color-text-primary); + display: flex; align-items: center; gap: 8px; +} +.mat-step[data-state="completed"] .mat-step__name { color: var(--color-text-secondary); } +.mat-step[data-state="future"] .mat-step__name { color: var(--color-text-tertiary); } + +.mat-step__pill { + font-size: 11px; padding: 2px 8px; border-radius: var(--radius-pill); + text-transform: uppercase; letter-spacing: 0.06em; font-weight: var(--font-weight-semibold); +} +.mat-step__pill--current { background: var(--color-primary-100); color: var(--color-primary-700); } +.mat-step__pill--complete { background: transparent; color: var(--color-state-success); border: 1px solid currentColor; } + +.mat-step__desc { + font-size: var(--font-size-sm); + color: var(--color-text-secondary); + margin-top: 2px; + max-width: 60ch; +} + +.mat-step__progress { + margin-top: 6px; + display: flex; align-items: center; gap: 8px; + font-size: 12px; color: var(--color-text-tertiary); +} +.mat-step__progress-bar { + flex: 1; height: 4px; + background: var(--color-bg-soft); + border-radius: 2px; + overflow: hidden; + max-width: 200px; +} +.mat-step__progress-fill { height: 100%; background: var(--color-primary-500); border-radius: 2px; } + +/* ========================================================================= + 5. Classify-and-Transform / 5-Bucket-Sorter (.cls-sorter) + ========================================================================= */ +.cls-sorter { display: flex; flex-direction: column; gap: var(--space-4); } + +.cls-input { + background: var(--color-surface); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-md); + padding: var(--space-3); +} +.cls-input textarea { + width: 100%; min-height: 100px; + font-family: var(--font-family-sans); + font-size: var(--font-size-sm); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-sm); + padding: var(--space-2) var(--space-3); + background: var(--color-bg); + color: var(--color-text-primary); + resize: vertical; +} +.cls-input textarea:focus { outline: none; box-shadow: var(--shadow-focus); border-color: var(--color-border-focus); } + +.cls-buckets { + display: grid; + grid-template-columns: repeat(5, 1fr); + gap: var(--space-3); +} +@media (max-width: 1100px) { .cls-buckets { grid-template-columns: repeat(3, 1fr); } } +@media (max-width: 720px) { .cls-buckets { grid-template-columns: repeat(2, 1fr); } } +@media (max-width: 460px) { .cls-buckets { grid-template-columns: 1fr; } } + +.cls-bucket { + background: var(--color-surface); + border: 1px solid var(--color-border-subtle); + border-top-width: 4px; + border-radius: var(--radius-md); + padding: var(--space-3); + display: flex; flex-direction: column; gap: var(--space-2); + min-height: 200px; +} +.cls-bucket[data-egnethet="lav"] { border-top-color: var(--color-text-tertiary); } +.cls-bucket[data-egnethet="medium"] { border-top-color: var(--color-state-info); } +.cls-bucket[data-egnethet="hoy"] { border-top-color: var(--color-state-success); } + +.cls-bucket__head { + display: flex; flex-direction: column; gap: 2px; + padding-bottom: var(--space-2); + border-bottom: 1px solid var(--color-border-subtle); +} +.cls-bucket__title { font-size: var(--font-size-sm); font-weight: var(--font-weight-semibold); color: var(--color-text-primary); } +.cls-bucket__egnethet { + font-size: 10px; text-transform: uppercase; letter-spacing: 0.08em; + color: var(--color-text-tertiary); font-weight: var(--font-weight-semibold); +} +.cls-bucket[data-egnethet="lav"] .cls-bucket__egnethet { color: var(--color-text-tertiary); } +.cls-bucket[data-egnethet="medium"] .cls-bucket__egnethet { color: var(--color-state-info); } +.cls-bucket[data-egnethet="hoy"] .cls-bucket__egnethet { color: var(--color-state-success); } + +.cls-item { + background: var(--color-bg-soft); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-sm); + padding: 6px 8px; + font-size: 12px; + color: var(--color-text-primary); + cursor: grab; + display: flex; flex-direction: column; gap: 2px; +} +.cls-item__action { + font-size: 10px; text-transform: uppercase; letter-spacing: 0.06em; + color: var(--color-text-tertiary); font-weight: var(--font-weight-medium); +} +.cls-bucket__action { + margin-top: auto; + padding-top: var(--space-2); + border-top: 1px dashed var(--color-border-subtle); +} +.cls-bucket__empty { + font-size: 12px; color: var(--color-text-tertiary); + font-style: italic; + text-align: center; + padding: var(--space-3); +} + +/* ========================================================================= + 6. Cycle Position Ribbon (.cycle-ribbon) + ========================================================================= */ +.cycle-ribbon { + position: relative; + background: var(--color-surface); + border-bottom: 1px solid var(--color-border-subtle); + padding: 8px var(--space-5); + display: flex; align-items: center; gap: var(--space-4); + font-size: 13px; + cursor: pointer; + overflow: hidden; +} +.cycle-ribbon::before { + content: ""; position: absolute; inset: 0; + background: var(--color-state-info); + opacity: 0.06; + width: var(--cycle-progress, 0%); + transition: width var(--duration-normal); +} +.cycle-ribbon[data-phase="planning"] { border-bottom-color: var(--color-state-info); } +.cycle-ribbon[data-phase="planning"]::before { background: var(--color-state-info); } +.cycle-ribbon[data-phase="execution"] { border-bottom-color: var(--color-state-success); } +.cycle-ribbon[data-phase="execution"]::before { background: var(--color-state-success); } +.cycle-ribbon[data-phase="retrospective_prep"] { border-bottom-color: var(--color-severity-medium); } +.cycle-ribbon[data-phase="retrospective_prep"]::before { background: var(--color-severity-medium); } + +.cycle-ribbon > * { position: relative; z-index: 1; } +.cycle-ribbon__id { font-family: var(--font-family-mono); font-weight: var(--font-weight-semibold); color: var(--color-text-primary); white-space: nowrap; flex-shrink: 0; } +.cycle-ribbon__week { color: var(--color-text-secondary); font-family: var(--font-family-mono); white-space: nowrap; flex-shrink: 0; } +.cycle-ribbon__phase { + font-size: 11px; padding: 2px 8px; + border-radius: var(--radius-pill); + text-transform: uppercase; letter-spacing: 0.06em; + font-weight: var(--font-weight-semibold); + white-space: nowrap; flex-shrink: 0; +} +.cycle-ribbon[data-phase="planning"] .cycle-ribbon__phase { background: var(--color-primary-100); color: var(--color-primary-700); } +.cycle-ribbon[data-phase="execution"] .cycle-ribbon__phase { background: var(--color-severity-low-soft); color: var(--color-severity-low-on); } +.cycle-ribbon[data-phase="retrospective_prep"] .cycle-ribbon__phase { background: var(--color-severity-medium-soft); color: var(--color-severity-medium-on); } +.cycle-ribbon__msg { color: var(--color-text-secondary); flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.cycle-ribbon__chev { color: var(--color-text-tertiary); transition: transform var(--duration-fast); } +.cycle-ribbon[aria-expanded="true"] .cycle-ribbon__chev { transform: rotate(180deg); } + +.cycle-ribbon__panel { + background: var(--color-bg-soft); + border-bottom: 1px solid var(--color-border-subtle); + padding: var(--space-4) var(--space-5); + display: none; + font-size: var(--font-size-sm); +} +.cycle-ribbon__panel[data-open="true"] { display: block; } + +@media (max-width: 720px) { + .cycle-ribbon__msg { display: none; } +} + +/* ========================================================================= + 7. Persistent-Antipattern Badge (.pap-badge) + ========================================================================= */ +.pap-badge { + display: inline-flex; align-items: center; gap: 6px; + padding: 4px 10px; + background: var(--color-surface); + border: 1px solid var(--color-severity-critical); + border-radius: var(--radius-pill); + font-size: 12px; + font-weight: var(--font-weight-medium); + color: var(--color-severity-critical); + cursor: pointer; + position: relative; +} +.pap-badge::before { + content: ""; + width: 8px; height: 8px; + border-radius: 50%; + background: var(--color-severity-critical); + animation: pap-pulse 2.4s var(--ease-default) infinite; +} +@keyframes pap-pulse { + 0%, 100% { opacity: 1; transform: scale(1); } + 50% { opacity: 0.45; transform: scale(0.7); } +} +@media (prefers-reduced-motion: reduce) { + .pap-badge::before { animation: none; opacity: 1; } +} +.pap-badge__count { font-family: var(--font-family-mono); font-weight: var(--font-weight-semibold); } + +.pap-detail { + margin-top: var(--space-3); + background: var(--color-surface); + border: 1px solid var(--color-severity-critical); + border-left-width: 4px; + border-radius: var(--radius-md); + padding: var(--space-4); + display: none; +} +.pap-detail[data-open="true"] { display: block; } +.pap-detail h4 { margin: 0 0 4px; color: var(--color-severity-critical); font-size: var(--font-size-md); } +.pap-detail__cycles { display: flex; gap: 4px; flex-wrap: wrap; margin: var(--space-2) 0; } +.pap-detail__cycle { + font-family: var(--font-family-mono); + font-size: 11px; + padding: 2px 6px; + background: var(--color-bg-soft); + border-radius: var(--radius-sm); + color: var(--color-text-secondary); +} +.pap-detail__rec { + background: var(--color-bg-soft); + border-radius: var(--radius-sm); + padding: var(--space-2) var(--space-3); + margin-top: var(--space-2); + font-size: var(--font-size-sm); + color: var(--color-text-primary); +} + +/* one-shot variant */ +.pap-badge--oneshot { + border-style: dashed; + border-color: var(--color-severity-medium); + color: var(--color-severity-medium); +} +.pap-badge--oneshot::before { display: none; } + +/* ========================================================================= + 8. Suppressed-Signals Panel (.suppressed) + ========================================================================= */ +.suppressed { + background: var(--color-bg-soft); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-md); + overflow: hidden; +} +.suppressed__head { + width: 100%; + display: flex; align-items: center; gap: var(--space-3); + padding: var(--space-3) var(--space-4); + background: transparent; + border: 0; + cursor: pointer; + font-family: inherit; + text-align: left; + color: var(--color-text-secondary); +} +.suppressed__head:hover { background: var(--color-surface-sunken); color: var(--color-text-primary); } +.suppressed__head:focus-visible { outline: none; box-shadow: var(--shadow-focus); } +.suppressed__chev { color: var(--color-text-tertiary); transition: transform var(--duration-fast); } +.suppressed[aria-expanded="true"] .suppressed__chev { transform: rotate(90deg); } +.suppressed__label { font-size: var(--font-size-sm); } +.suppressed__count { + font-family: var(--font-family-mono); + font-size: 12px; + background: var(--color-surface); + padding: 2px 8px; + border-radius: var(--radius-pill); + color: var(--color-text-secondary); + border: 1px solid var(--color-border-subtle); + margin-left: auto; +} + +.suppressed__body { + display: none; + padding: 0 var(--space-4) var(--space-4); +} +.suppressed[aria-expanded="true"] .suppressed__body { display: block; } + +.suppressed-group { + background: var(--color-surface); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-sm); + padding: var(--space-3); +} +.suppressed-group + .suppressed-group { margin-top: var(--space-2); } +.suppressed-group__head { + display: flex; justify-content: space-between; align-items: center; gap: 8px; + margin-bottom: 4px; +} +.suppressed-group__reason { font-family: var(--font-family-mono); font-size: 12px; color: var(--color-text-tertiary); } +.suppressed-group__count { font-size: 11px; color: var(--color-text-tertiary); } +.suppressed-group__desc { font-size: var(--font-size-sm); color: var(--color-text-secondary); margin: 0 0 6px; } +.suppressed-group__examples { + display: flex; gap: 4px; flex-wrap: wrap; +} +.suppressed-group__example { + font-family: var(--font-family-mono); + font-size: 11px; + background: var(--color-bg-soft); + padding: 2px 6px; + border-radius: var(--radius-sm); + color: var(--color-text-secondary); +} + +/* ========================================================================= + 9. ExpansionCard (Aksel) (.expansion) + ========================================================================= */ +.expansion { + background: var(--color-surface); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-md); + overflow: hidden; +} +.expansion + .expansion { margin-top: var(--space-2); } +.expansion__head { + width: 100%; + display: flex; align-items: flex-start; gap: var(--space-3); + padding: var(--space-3) var(--space-4); + background: transparent; + border: 0; + cursor: pointer; + font-family: inherit; + text-align: left; +} +.expansion__head:hover { background: var(--color-bg-soft); } +.expansion__head:focus-visible { outline: none; box-shadow: var(--shadow-focus); } +.expansion__title { flex: 1; } +.expansion__title-main { font-size: var(--font-size-md); color: var(--color-text-primary); font-weight: var(--font-weight-medium); } +.expansion__title-sub { font-size: var(--font-size-sm); color: var(--color-text-secondary); margin-top: 2px; } +.expansion__chev { + color: var(--color-text-tertiary); + transition: transform var(--duration-normal) var(--ease-default); + flex-shrink: 0; + margin-top: 2px; +} +.expansion[aria-expanded="true"] .expansion__chev { transform: rotate(180deg); } + +.expansion__body { + display: grid; + grid-template-rows: 0fr; + transition: grid-template-rows var(--duration-normal) var(--ease-default); +} +.expansion[aria-expanded="true"] .expansion__body { grid-template-rows: 1fr; } +.expansion__body-inner { overflow: hidden; } +.expansion__body-inner > div { + padding: 0 var(--space-4) var(--space-4); + border-top: 1px solid var(--color-border-subtle); + padding-top: var(--space-3); + margin-top: -1px; +} +@media (prefers-reduced-motion: reduce) { + .expansion__body { transition: none; } +} + +/* ========================================================================= + 10. ReadMore (Aksel) (.read-more) + ========================================================================= */ +.read-more { + display: inline; +} +.read-more__trigger { + display: inline-flex; align-items: center; gap: 4px; + background: transparent; + border: 0; + color: var(--color-text-link); + font-family: inherit; + font-size: inherit; + font-weight: var(--font-weight-medium); + cursor: pointer; + padding: 0; + text-decoration: underline; + text-decoration-thickness: 1px; + text-underline-offset: 3px; +} +.read-more__trigger:hover { color: var(--color-text-link-hover); } +.read-more__trigger:focus-visible { outline: none; box-shadow: var(--shadow-focus); border-radius: 2px; } +.read-more__chev { transition: transform var(--duration-fast); } +.read-more[aria-expanded="true"] .read-more__chev { transform: rotate(180deg); } +.read-more__body { display: none; margin-top: var(--space-2); } +.read-more[aria-expanded="true"] .read-more__body { display: block; } + +/* ========================================================================= + 11. FormProgress (Aksel multi-step skjema) (.form-progress) + ========================================================================= */ +.form-progress { + background: var(--color-surface); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-md); + padding: var(--space-4); + display: flex; flex-direction: column; gap: var(--space-3); + width: 280px; + position: sticky; + top: var(--space-4); +} +.form-progress__autosave { + display: flex; align-items: center; gap: 6px; + font-size: 12px; + color: var(--color-text-tertiary); + padding-bottom: var(--space-2); + border-bottom: 1px solid var(--color-border-subtle); +} +.form-progress__autosave-dot { + width: 6px; height: 6px; + border-radius: 50%; + background: var(--color-state-success); +} +.form-progress__steps { display: flex; flex-direction: column; gap: 2px; } +.fp-step { + display: grid; + grid-template-columns: 28px 1fr; + gap: var(--space-2); + align-items: start; + padding: 8px; + border-radius: var(--radius-sm); + text-align: left; + background: transparent; + border: 0; + cursor: pointer; + font-family: inherit; + position: relative; +} +.fp-step:hover { background: var(--color-bg-soft); } +.fp-step:focus-visible { outline: none; box-shadow: var(--shadow-focus); } +.fp-step[disabled] { cursor: not-allowed; opacity: 0.5; } + +.fp-step__num { + width: 22px; height: 22px; + border-radius: 50%; + display: flex; align-items: center; justify-content: center; + background: var(--color-surface); + border: 1.5px solid var(--color-border-moderate); + color: var(--color-text-tertiary); + font-size: 11px; + font-weight: var(--font-weight-semibold); +} +.fp-step[data-state="done"] .fp-step__num { + background: var(--color-state-success); + border-color: var(--color-state-success); + color: #fff; +} +.fp-step[data-state="in-progress"] .fp-step__num { + border-color: var(--color-primary-500); + color: var(--color-primary-700); + font-weight: var(--font-weight-bold); +} +.fp-step__name { font-size: var(--font-size-sm); color: var(--color-text-primary); font-weight: var(--font-weight-medium); } +.fp-step[data-state="done"] .fp-step__name { color: var(--color-text-secondary); font-weight: var(--font-weight-regular); } +.fp-step[data-state="in-progress"] .fp-step__name { color: var(--color-primary-700); font-weight: var(--font-weight-semibold); } + +.fp-step__progress { + margin-top: 4px; + font-size: 11px; + color: var(--color-text-tertiary); + display: flex; align-items: center; gap: 6px; +} +.fp-step__bar { + flex: 1; height: 3px; + background: var(--color-bg-soft); + border-radius: 2px; overflow: hidden; + max-width: 80px; +} +.fp-step__bar-fill { height: 100%; background: var(--color-primary-500); } + +.form-progress__remaining { + padding-top: var(--space-2); + border-top: 1px solid var(--color-border-subtle); + font-size: 12px; color: var(--color-text-tertiary); + display: flex; justify-content: space-between; +} + +/* ========================================================================= + 12. Aspirational vs Committed Visual (.okr-mode) + Modifier added to OKR Objective cards + ========================================================================= */ +.okr-mode { + position: relative; + background: var(--color-surface); + border: 1px solid var(--color-border-subtle); + border-radius: var(--radius-md); + padding: var(--space-4); +} +.okr-mode__gauge { + position: relative; + width: 88px; height: 88px; + display: flex; align-items: center; justify-content: center; + flex-shrink: 0; +} +.okr-mode__gauge svg { position: absolute; inset: 0; transform: rotate(-90deg); width: 100%; height: 100%; } +.okr-mode__gauge circle.gauge-bg { fill: none; stroke: var(--color-border-subtle); stroke-width: 6; } +.okr-mode__gauge circle.gauge-fill { fill: none; stroke: var(--color-state-success); stroke-width: 6; stroke-linecap: round; } +.okr-mode__gauge .gauge-value { font-family: var(--font-family-mono); font-size: 22px; font-weight: var(--font-weight-bold); color: var(--color-text-primary); position: relative; z-index: 1; } + +/* aspirational variant — dashed stroke */ +.okr-mode[data-mode="aspirational"] .okr-mode__gauge circle.gauge-fill { + stroke: var(--color-scope-okr); + stroke-dasharray: 6 4; +} +.okr-mode__badge { + position: absolute; + top: var(--space-2); right: var(--space-2); + font-size: 10px; font-weight: var(--font-weight-bold); letter-spacing: 0.08em; + padding: 2px 8px; + border-radius: var(--radius-sm); +} +.okr-mode[data-mode="aspirational"] .okr-mode__badge { + background: transparent; + color: var(--color-scope-okr); + border: 1px dashed var(--color-scope-okr); +} +.okr-mode[data-mode="committed"] .okr-mode__badge { + background: var(--color-primary-700); + color: #fff; +} +.okr-mode__row { display: flex; gap: var(--space-4); align-items: center; } +.okr-mode__objective { font-size: var(--font-size-md); color: var(--color-text-primary); flex: 1; } +.okr-mode__hint { font-size: 12px; color: var(--color-text-tertiary); margin-top: 4px; } diff --git a/shared/playground-design-system/fonts.css b/shared/playground-design-system/fonts.css new file mode 100644 index 0000000..3f375eb --- /dev/null +++ b/shared/playground-design-system/fonts.css @@ -0,0 +1,83 @@ +/* + * Self-hosted web fonts for Playground Design System. + * + * All three families are licensed under SIL Open Font License 1.1. + * Full license text and provenance: ./fonts/LICENSES.md + * + * Why self-hosted: + * - No external requests (no fonts.googleapis.com, no IP/UA leakage). + * - Works offline / behind air-gapped firewalls. + * - GDPR-compliant for Norwegian public-sector deployments. + * + * Bundle size: ~940 KB total across 9 woff2 files. + * Loaded via font-display: swap to avoid FOIT. + */ + +/* ========== Inter (UI / body) ========== */ +@font-face { + font-family: "Inter"; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url("./fonts/Inter-Regular.woff2") format("woff2"); +} +@font-face { + font-family: "Inter"; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url("./fonts/Inter-Medium.woff2") format("woff2"); +} +@font-face { + font-family: "Inter"; + font-style: normal; + font-weight: 600; + font-display: swap; + src: url("./fonts/Inter-SemiBold.woff2") format("woff2"); +} +@font-face { + font-family: "Inter"; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url("./fonts/Inter-Bold.woff2") format("woff2"); +} + +/* ========== JetBrains Mono (code) ========== */ +@font-face { + font-family: "JetBrains Mono"; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url("./fonts/JetBrainsMono-Regular.woff2") format("woff2"); +} +@font-face { + font-family: "JetBrains Mono"; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url("./fonts/JetBrainsMono-Medium.woff2") format("woff2"); +} +@font-face { + font-family: "JetBrains Mono"; + font-style: normal; + font-weight: 600; + font-display: swap; + src: url("./fonts/JetBrainsMono-SemiBold.woff2") format("woff2"); +} + +/* ========== Source Serif 4 (occasional editorial accents) ========== */ +@font-face { + font-family: "Source Serif 4"; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url("./fonts/SourceSerif4-Regular.woff2") format("woff2"); +} +@font-face { + font-family: "Source Serif 4"; + font-style: normal; + font-weight: 600; + font-display: swap; + src: url("./fonts/SourceSerif4-Semibold.woff2") format("woff2"); +} diff --git a/shared/playground-design-system/fonts/Inter-Bold.woff2 b/shared/playground-design-system/fonts/Inter-Bold.woff2 new file mode 100644 index 0000000..0f1b157 Binary files /dev/null and b/shared/playground-design-system/fonts/Inter-Bold.woff2 differ diff --git a/shared/playground-design-system/fonts/Inter-Medium.woff2 b/shared/playground-design-system/fonts/Inter-Medium.woff2 new file mode 100644 index 0000000..0fd2ee7 Binary files /dev/null and b/shared/playground-design-system/fonts/Inter-Medium.woff2 differ diff --git a/shared/playground-design-system/fonts/Inter-Regular.woff2 b/shared/playground-design-system/fonts/Inter-Regular.woff2 new file mode 100644 index 0000000..b8699af Binary files /dev/null and b/shared/playground-design-system/fonts/Inter-Regular.woff2 differ diff --git a/shared/playground-design-system/fonts/Inter-SemiBold.woff2 b/shared/playground-design-system/fonts/Inter-SemiBold.woff2 new file mode 100644 index 0000000..95c48b1 Binary files /dev/null and b/shared/playground-design-system/fonts/Inter-SemiBold.woff2 differ diff --git a/shared/playground-design-system/fonts/JetBrainsMono-Medium.woff2 b/shared/playground-design-system/fonts/JetBrainsMono-Medium.woff2 new file mode 100644 index 0000000..669d04c Binary files /dev/null and b/shared/playground-design-system/fonts/JetBrainsMono-Medium.woff2 differ diff --git a/shared/playground-design-system/fonts/JetBrainsMono-Regular.woff2 b/shared/playground-design-system/fonts/JetBrainsMono-Regular.woff2 new file mode 100644 index 0000000..40da427 Binary files /dev/null and b/shared/playground-design-system/fonts/JetBrainsMono-Regular.woff2 differ diff --git a/shared/playground-design-system/fonts/JetBrainsMono-SemiBold.woff2 b/shared/playground-design-system/fonts/JetBrainsMono-SemiBold.woff2 new file mode 100644 index 0000000..5ead7b0 Binary files /dev/null and b/shared/playground-design-system/fonts/JetBrainsMono-SemiBold.woff2 differ diff --git a/shared/playground-design-system/fonts/LICENSE-Inter.txt b/shared/playground-design-system/fonts/LICENSE-Inter.txt new file mode 100644 index 0000000..9b2ca37 --- /dev/null +++ b/shared/playground-design-system/fonts/LICENSE-Inter.txt @@ -0,0 +1,92 @@ +Copyright (c) 2016 The Inter Project Authors (https://github.com/rsms/inter) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION AND CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/shared/playground-design-system/fonts/LICENSE-JetBrainsMono.txt b/shared/playground-design-system/fonts/LICENSE-JetBrainsMono.txt new file mode 100644 index 0000000..8bee414 --- /dev/null +++ b/shared/playground-design-system/fonts/LICENSE-JetBrainsMono.txt @@ -0,0 +1,93 @@ +Copyright 2020 The JetBrains Mono Project Authors (https://github.com/JetBrains/JetBrainsMono) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +https://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/shared/playground-design-system/fonts/LICENSE-SourceSerif4.md b/shared/playground-design-system/fonts/LICENSE-SourceSerif4.md new file mode 100644 index 0000000..ebe298c --- /dev/null +++ b/shared/playground-design-system/fonts/LICENSE-SourceSerif4.md @@ -0,0 +1,93 @@ +Copyright 2014 - 2023 Adobe (http://www.adobe.com/), with Reserved Font Name ‘Source’. All Rights Reserved. Source is a trademark of Adobe in the United States and/or other countries. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. + +This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/shared/playground-design-system/fonts/LICENSES.md b/shared/playground-design-system/fonts/LICENSES.md new file mode 100644 index 0000000..0389aa8 --- /dev/null +++ b/shared/playground-design-system/fonts/LICENSES.md @@ -0,0 +1,42 @@ +# Font Licenses + +All three font families bundled with Playground Design System are licensed +under the SIL Open Font License, Version 1.1 (OFL-1.1). They are free to +use, modify, embed, and redistribute under the terms of OFL-1.1. + +Full license text per family: + +- **Inter** (Regular, Medium, SemiBold, Bold) — `LICENSE-Inter.txt` + Copyright (c) 2016 The Inter Project Authors + Source: https://github.com/rsms/inter + Version bundled: 4.0 + +- **JetBrains Mono** (Regular, Medium, SemiBold) — `LICENSE-JetBrainsMono.txt` + Copyright 2020 The JetBrains Mono Project Authors + Source: https://github.com/JetBrains/JetBrainsMono + Version bundled: 2.304 + +- **Source Serif 4** (Regular, Semibold) — `LICENSE-SourceSerif4.md` + Copyright 2014–2023 Adobe (Reserved Font Name "Source") + Source: https://github.com/adobe-fonts/source-serif + Version bundled: 4.005 + +## Provenance + +Files in this directory were obtained from the upstream release artifacts +linked above on 2026-05-03. Source Serif 4 woff2 files were generated locally +from the desktop OTF release using `fonttools ttLib.woff2 compress`; all +others are unmodified from upstream webfont releases. + +## Why bundled + +These fonts ship with the design system to eliminate runtime requests to +external CDNs (e.g., fonts.googleapis.com). This guarantees: + +- No data leakage about end-user IPs / User-Agents to third parties. +- GDPR compliance for Norwegian public-sector deployments. +- Functioning Playgrounds in offline / air-gapped environments. + +Each Playground HTML loads `../shared/playground-design-system/fonts.css`, +which declares all `@font-face` rules pointing at the .woff2 files in this +directory. diff --git a/shared/playground-design-system/fonts/SourceSerif4-Regular.woff2 b/shared/playground-design-system/fonts/SourceSerif4-Regular.woff2 new file mode 100644 index 0000000..5858db3 Binary files /dev/null and b/shared/playground-design-system/fonts/SourceSerif4-Regular.woff2 differ diff --git a/shared/playground-design-system/fonts/SourceSerif4-Semibold.woff2 b/shared/playground-design-system/fonts/SourceSerif4-Semibold.woff2 new file mode 100644 index 0000000..3bb9b6c Binary files /dev/null and b/shared/playground-design-system/fonts/SourceSerif4-Semibold.woff2 differ diff --git a/shared/playground-examples/components/aspirational-committed.html b/shared/playground-examples/components/aspirational-committed.html new file mode 100644 index 0000000..77ed20d --- /dev/null +++ b/shared/playground-examples/components/aspirational-committed.html @@ -0,0 +1,100 @@ + + + + + +Aspirational vs Committed · Tier 3 supp + + + + + + + + +
+ PPlayground + / Komponenter / Aspirational vs Committed +
+ +
+
+ OKR · visuell modus-skille +

Aspirational vs Committed

+

Modifier på Objective-card. Aspirational (0,7 = success) har stiplet ring + ASP-badge. Committed (1,0 = expected) har solid ring + COM-badge.

+
+ +
+ +
+ ASP +
+
+ + 0,60 +
+
+
Bli landets ledende kommune på AI-assistert saksbehandling innen 2027
+
Aspirasjon — 0,7 regnes som vellykket
+
+
+
+ +
+ COM +
+
+ + 0,90 +
+
+
Innfør sentralisert sensitivity-label-policy for alle 1 850 ansatte før 30. juni
+
Committed — 1,0 forventes oppnådd
+
+
+
+ +
+ ASP +
+
+ + 0,30 +
+
+
Halver gjennomsnittlig saksbehandlings­tid på byggesøknader
+
Aspirasjon — 0,3 så langt, fortsatt rom for å akselerere
+
+
+
+ +
+ COM +
+
+ + 1,00 +
+
+
Levér T2-rapport til kommunestyret senest 5. september
+
Committed — oppnådd
+
+
+
+ +
+
+ + diff --git a/shared/playground-examples/components/classify-transform.html b/shared/playground-examples/components/classify-transform.html new file mode 100644 index 0000000..6f26d42 --- /dev/null +++ b/shared/playground-examples/components/classify-transform.html @@ -0,0 +1,86 @@ + + + + + +Classify & Transform · Tier 3 supp + + + + + + + + +
+ PPlayground + / Komponenter / Classify-and-Transform +
+ +
+
+ OKR · /okr:skriv strategi-til-OKR +

5-bucket-sorter

+

Lim inn tildelingsbrev øverst — hver krav-setning klassifiseres etter OKR-egnethet (lav, medium, høy).

+
+ +
+
+ +
+ + 6 setninger funnet +
+
+ +
+
+
+ + + + diff --git a/shared/playground-examples/components/cycle-ribbon.html b/shared/playground-examples/components/cycle-ribbon.html new file mode 100644 index 0000000..171154a --- /dev/null +++ b/shared/playground-examples/components/cycle-ribbon.html @@ -0,0 +1,90 @@ + + + + + +Cycle Position Ribbon · Tier 3 supp + + + + + + + + +
+ PPlayground + / Komponenter / Cycle Position Ribbon +
+ + + +
+
+
+
Periode
+ 1. mai – 31. august 2026 +
+
+
Fase
+ Planning (uke 1–2) +
Execution starter uke 3, retrospective_prep fra uke 14.
+
+
+
Neste milepel
+ Team-check-in 1 +
Senest 24. mai 2026 (uke 5).
+
+
+
+ +
+
+ OKR · persistent header +

Cycle Position Ribbon

+

Persistent stripe under app-header som viser hvor i tertialen brukeren er. Klikk for detaljpanel.

+
+ +

Alle 3 faser

+ +
+
+ T2-2026 + Uke 2 / 16 + Planning + Sett mål og forankre med ledelse. + +
+
+ T2-2026 + Uke 8 / 16 + Execution + Halvveis. Halvveissamtale anbefales denne uka. + +
+
+ T2-2026 + Uke 14 / 16 + Retro-prep + Forbered scoring og retrospektiv. Frist for KR-scoring: 25. august. + +
+
+
+ + + + diff --git a/shared/playground-examples/components/expansion-card.html b/shared/playground-examples/components/expansion-card.html new file mode 100644 index 0000000..4e5c4eb --- /dev/null +++ b/shared/playground-examples/components/expansion-card.html @@ -0,0 +1,85 @@ + + + + + +ExpansionCard · Tier 3 supp + + + + + + + + +
+ PPlayground + / Komponenter / ExpansionCard +
+ +
+
+ Aksel · progressive disclosure +

ExpansionCard

+

Skjul sekundær informasjon bak klikkbar overskrift. Animert utvidelse respekterer prefers-reduced-motion.

+
+ + + + + + +
+ + + + diff --git a/shared/playground-examples/components/fleet-overview.html b/shared/playground-examples/components/fleet-overview.html new file mode 100644 index 0000000..eac3c64 --- /dev/null +++ b/shared/playground-examples/components/fleet-overview.html @@ -0,0 +1,102 @@ + + + + + +Fleet-Overview · Tier 3 supp + + + + + + + + +
+ PPlayground + / Komponenter / Fleet-Overview +
+ +
+
+ llm-security · /security dashboard +

Fleet-Overview

+

Cross-project posture på én skjerm. 4 kolonner desktop → 2 → 1.

+
+ +
+ Sortér + + + + Filter + + + + 12 prosjekter +
+ +
+
+ + + + diff --git a/shared/playground-examples/components/form-progress.html b/shared/playground-examples/components/form-progress.html new file mode 100644 index 0000000..39942b3 --- /dev/null +++ b/shared/playground-examples/components/form-progress.html @@ -0,0 +1,81 @@ + + + + + +FormProgress · Tier 3 supp + + + + + + + + + +
+ PPlayground + / Komponenter / FormProgress +
+ +
+
+ ms-ai-architect onboarding · OKR /oppsett full · DPIA +

FormProgress

+

Vertikal sidebar for store skjema. Autosave-status, ferdig-prosent per steg, estimert resterende tid. Ikke å forveksle med horisontal stepper.

+
+ +
+ + +
+
Steg 3 av 5
+

Datakilder & klassifisering

+

Skjemaet hadde 12 felt — 7 utfylt, 5 igjen. Estimert ferdig om 5 minutter.

+
[Skjema-felt placeholder — i produksjon: input/select/textarea]
+
+
+
+ + diff --git a/shared/playground-examples/components/kanban.html b/shared/playground-examples/components/kanban.html new file mode 100644 index 0000000..fcc5ea2 --- /dev/null +++ b/shared/playground-examples/components/kanban.html @@ -0,0 +1,144 @@ + + + + + +Kanban · Keep/Review/Remove · Tier 3 supp + + + + + + + + + +
+ PPlayground + / Komponenter / Kanban: Keep/Review/Remove +
+ +
+
+ llm-security · /security plugin-audit +

Kanban: Behold / Vurder / Fjern

+

Klassifisér installerte plugins/MCP-servere etter trust. Klikk-flytt mellom kolonner.

+
+ +
+
+ + + + + + diff --git a/shared/playground-examples/components/maturity-ladder.html b/shared/playground-examples/components/maturity-ladder.html new file mode 100644 index 0000000..2235ad0 --- /dev/null +++ b/shared/playground-examples/components/maturity-ladder.html @@ -0,0 +1,97 @@ + + + + + +Maturity-Ladder · Tier 3 supp + + + + + + + + + +
+ PPlayground + / Komponenter / Maturity-Ladder +
+ +
+
+ OKR · config-audit · security +

Maturity-Ladder

+

Vertikal stepper med rik beskrivelse. Current step har progress-ring (her 65 %).

+
+ +
+
+

OKR-modenhet (4 nivåer)

+
+
+ +
+
Utforsker Fullført
+
Eksperimenterer med OKR i 1–2 team. Ingen formell rytme.
+
+
+
+ +
+
Pilot
+
OKR i én avdeling. Kvartalsrytme etablert. Ledelse engasjert.
+
65 %til Skalering
+
+
+
+ +
+
Skalering
+
OKR rullet ut til hele organisasjonen. Cross-team alignment.
+
+
+
+ +
+
Moden
+
OKR er drift. Strategisk forankring fra Stortingsmelding til team-OKR.
+
+
+
+
+ +
+

Config-modenhet (5 nivåer)

+
+
+
Bare Fullført
+
Defaults overalt. Ingen sentralisert konfig.
+
+
Configured Fullført
+
Eksplisitte verdier per miljø. Ingen drift-deteksjon.
+
+
Structured
+
Skjema-validert konfig. Versjonert i Git. Endringssporbarhet.
+
30 %til Automated
+
+
Automated
+
CI-validering. Auto-rollback ved feil. Drift-detektor.
+
+
Governed
+
Policy-as-code. Audit-trail. Approval-workflows for prod.
+
+
+
+
+ + diff --git a/shared/playground-examples/components/persistent-antipattern.html b/shared/playground-examples/components/persistent-antipattern.html new file mode 100644 index 0000000..54c7adf --- /dev/null +++ b/shared/playground-examples/components/persistent-antipattern.html @@ -0,0 +1,99 @@ + + + + + +Persistent-Antipattern Badge · Tier 3 supp + + + + + + + + +
+ PPlayground + / Komponenter / Persistent-Antipattern Badge +
+ +
+
+ OKR · /okr:analyse cross-cycle +

Persistent-Antipattern Badge

+

Markerer antipatterns som har dukket opp i 2+ påfølgende sykluser. Pulserende prikk skiller seg fra one-shot.

+
+ +

I bruk i en finding-tabell

+ + + + + + + + + + + + + + + + + + + + + + + + + +
AntipatternFunnet iStatus
Aktivitetsfokus i KRT1-25 · T2-25 · T3-25 · T1-26 · T2-26 + +
Sandbagging av target-verdierT2-25 · T3-25 · T1-26 + +
For mange KR per ObjectiveT2-26 + Én syklus +
+ +
+

Aktivitetsfokus i KR

+

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.

+
+ T1-2025 · 4 forekomster + T2-2025 · 3 forekomster + T3-2025 · 5 forekomster + T1-2026 · 6 forekomster + T2-2026 · 4 forekomster +
+
Anbefaling: Vurder OKR-coaching eller retrospective-fokus på outcome vs activity. Spør "Hva endrer seg for innbyggeren hvis dette KR-et oppfylles?"
+
+ +
+

Sandbagging av target-verdier

+

Targets satt så lavt at de oppnås uten reell innsats. Score > 0,9 to sykluser på rad uten endring i baseline.

+
+ T2-2025 + T3-2025 + T1-2026 +
+
Anbefaling: Innfør stretch-target som komplement, eller vurder aspirational vs committed-skille (se OKR-mode).
+
+
+ + + + diff --git a/shared/playground-examples/components/read-more.html b/shared/playground-examples/components/read-more.html new file mode 100644 index 0000000..5ea5353 --- /dev/null +++ b/shared/playground-examples/components/read-more.html @@ -0,0 +1,59 @@ + + + + + +ReadMore · Tier 3 supp + + + + + + + + +
+ PPlayground + / Komponenter / ReadMore +
+ +
+
+ Aksel · inline disclosure +

ReadMore

+

Inline-trigger for å skjule lange forklaringer mid-tekst.

+
+ +
+

Sensitivity Labels brukes til å klassifisere dokumenter etter konfidensialitetsnivå. + +

+ +

Schrems II-vurdering kreves for cross-tenant data-flyt. + +

+
+
+ + + + diff --git a/shared/playground-examples/components/sankey-toxic-flow.html b/shared/playground-examples/components/sankey-toxic-flow.html new file mode 100644 index 0000000..3126869 --- /dev/null +++ b/shared/playground-examples/components/sankey-toxic-flow.html @@ -0,0 +1,117 @@ + + + + + +Toxic-Flow Chain · Tier 3 supp + + + + + + + + +
+ PPlayground + / Komponenter / Toxic-Flow Chain (TFA) +
+ +
+
+ llm-security · TFA +

Toxic-Flow Chain

+

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.

+
+ +

TFA-2026-118-001 — BLOCK

+
+ BLOCK + + + + + + + + + + +
+ +

TFA-2026-118-002 — WARN (mitigation present)

+
+ WARN + + + + + +
+ +

TFA-2026-118-003 — ALLOW

+
+ ALLOW + + + + + +
+
+ + diff --git a/shared/playground-examples/components/suppressed-signals.html b/shared/playground-examples/components/suppressed-signals.html new file mode 100644 index 0000000..c23014f --- /dev/null +++ b/shared/playground-examples/components/suppressed-signals.html @@ -0,0 +1,74 @@ + + + + + +Suppressed-Signals · Tier 3 supp + + + + + + + + +
+ PPlayground + / Komponenter / Suppressed-Signals Panel +
+ +
+
+ llm-security · ultraplan-local +

Suppressed-Signals Panel

+

Synlig — men sammenklappet — liste over funn som ble nedgradert eller fjernet, og hvorfor. Aldri skjult i en meny: tillit krever transparens.

+
+ +

Etter funn-listen, før footer:

+ + +
+ + + + diff --git a/shared/playground-examples/index.html b/shared/playground-examples/index.html index d532fd4..ca1f597 100644 --- a/shared/playground-examples/index.html +++ b/shared/playground-examples/index.html @@ -8,9 +8,7 @@ - - - +