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>
866 lines
44 KiB
HTML
866 lines
44 KiB
HTML
<!doctype html>
|
||
<html lang="nb">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
<title>OKR live-writer — Bærum kommune — T2 2026</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/fonts.css" />
|
||
<style>
|
||
.layout { display: grid; grid-template-rows: auto 1fr; min-height: 100vh; }
|
||
.page { padding: var(--space-8) 0 var(--space-16); }
|
||
.page__header {
|
||
display: flex; justify-content: space-between; align-items: flex-end;
|
||
gap: var(--space-6); margin-bottom: var(--space-6);
|
||
border-bottom: 1px solid var(--color-border-subtle);
|
||
padding-bottom: var(--space-4);
|
||
}
|
||
.page__title { display: flex; flex-direction: column; gap: 4px; }
|
||
.page__eyebrow {
|
||
font-size: var(--font-size-xs); text-transform: uppercase; letter-spacing: 0.1em;
|
||
color: var(--color-scope-okr); font-weight: var(--font-weight-semibold);
|
||
}
|
||
.page__meta { display: flex; gap: var(--space-4); font-size: var(--font-size-sm); color: var(--color-text-secondary); }
|
||
.page__meta-item { display: flex; gap: 6px; align-items: baseline; }
|
||
.page__meta-label { color: var(--color-text-tertiary); font-size: var(--font-size-xs); text-transform: uppercase; letter-spacing: 0.06em; }
|
||
|
||
/* Two-pane writer layout */
|
||
.writer {
|
||
display: grid;
|
||
grid-template-columns: 1.4fr 1fr;
|
||
gap: var(--space-6);
|
||
align-items: start;
|
||
}
|
||
.pane {
|
||
background: var(--color-surface);
|
||
border: 1px solid var(--color-border-subtle);
|
||
border-radius: var(--radius-md);
|
||
overflow: hidden;
|
||
}
|
||
.pane__head {
|
||
padding: 10px 16px;
|
||
background: var(--color-bg-soft);
|
||
border-bottom: 1px solid var(--color-border-subtle);
|
||
display: flex; justify-content: space-between; align-items: center;
|
||
gap: var(--space-3);
|
||
}
|
||
.pane__title {
|
||
font-size: var(--font-size-sm); font-weight: var(--font-weight-semibold);
|
||
color: var(--color-text-primary); margin: 0;
|
||
display: flex; align-items: center; gap: 8px;
|
||
}
|
||
.pane__title-eyebrow {
|
||
font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em;
|
||
color: var(--color-text-tertiary); font-weight: var(--font-weight-medium);
|
||
}
|
||
.pane__body { padding: var(--space-5); }
|
||
|
||
/* Editor styling */
|
||
.editor {
|
||
font-family: var(--font-family-serif);
|
||
font-size: 18px;
|
||
line-height: 1.7;
|
||
min-height: 380px;
|
||
outline: none;
|
||
}
|
||
.editor h2 {
|
||
font-family: var(--font-family-sans);
|
||
font-size: var(--font-size-lg);
|
||
font-weight: var(--font-weight-semibold);
|
||
margin: 0 0 var(--space-2);
|
||
color: var(--color-text-primary);
|
||
}
|
||
.editor .objective {
|
||
font-family: var(--font-family-serif);
|
||
font-size: 22px;
|
||
font-weight: 600;
|
||
line-height: 1.35;
|
||
margin-bottom: var(--space-5);
|
||
color: var(--color-text-primary);
|
||
}
|
||
.editor .kr {
|
||
margin: 0 0 var(--space-4);
|
||
padding: var(--space-3) var(--space-4);
|
||
background: var(--color-bg-soft);
|
||
border-radius: var(--radius-sm);
|
||
border-left: 3px solid var(--color-scope-okr);
|
||
position: relative;
|
||
}
|
||
.editor .kr-label {
|
||
font-family: var(--font-family-mono);
|
||
font-size: 11px;
|
||
color: var(--color-scope-okr);
|
||
font-weight: var(--font-weight-semibold);
|
||
letter-spacing: 0.06em;
|
||
margin-bottom: 4px;
|
||
display: block;
|
||
}
|
||
.editor .kr-text { font-family: var(--font-family-serif); font-size: 18px; line-height: 1.5; }
|
||
|
||
/* Inline highlight overlays in the editor */
|
||
.hl {
|
||
background-image: linear-gradient(to bottom, transparent 0, transparent 60%, var(--hl-color, rgba(191,135,0,0.25)) 60%, var(--hl-color, rgba(191,135,0,0.25)) 100%);
|
||
cursor: help;
|
||
border-bottom: 2px solid var(--hl-border, var(--color-severity-medium));
|
||
padding-bottom: 1px;
|
||
}
|
||
.hl[data-issue="missing-baseline"] { --hl-color: rgba(191,135,0,0.22); --hl-border: var(--color-severity-medium); }
|
||
.hl[data-issue="vague-verb"] { --hl-color: rgba(204,90,0,0.22); --hl-border: var(--color-severity-high); }
|
||
.hl[data-issue="activity"] { --hl-color: rgba(164,14,38,0.18); --hl-border: var(--color-severity-critical); }
|
||
.hl[data-issue="no-deadline"] { --hl-color: rgba(191,135,0,0.22); --hl-border: var(--color-severity-medium); }
|
||
.hl[data-issue="no-metric"] { --hl-color: rgba(204,90,0,0.22); --hl-border: var(--color-severity-high); }
|
||
|
||
/* Score header */
|
||
.score-strip {
|
||
display: grid;
|
||
grid-template-columns: auto 1fr auto;
|
||
gap: var(--space-5);
|
||
align-items: center;
|
||
padding: var(--space-5);
|
||
background: var(--color-surface);
|
||
border: 1px solid var(--color-border-subtle);
|
||
border-radius: var(--radius-md);
|
||
margin-bottom: var(--space-5);
|
||
}
|
||
.score-strip__num {
|
||
font-size: 48px;
|
||
font-weight: var(--font-weight-bold);
|
||
line-height: 1;
|
||
font-variant-numeric: tabular-nums;
|
||
letter-spacing: -0.02em;
|
||
color: var(--color-text-primary);
|
||
}
|
||
.score-strip__num small { font-size: 18px; color: var(--color-text-tertiary); font-weight: var(--font-weight-medium); }
|
||
.score-strip__bars { display: flex; flex-direction: column; gap: 6px; }
|
||
.score-strip__bar { display: grid; grid-template-columns: 70px 1fr 36px; gap: 8px; align-items: center; font-size: 12px; }
|
||
.score-strip__bar-label { color: var(--color-text-secondary); font-family: var(--font-family-mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.04em; }
|
||
.score-strip__bar-track { height: 6px; background: var(--color-surface-sunken); border-radius: var(--radius-pill); overflow: hidden; }
|
||
.score-strip__bar-fill { height: 100%; border-radius: var(--radius-pill); }
|
||
.score-strip__bar-num { font-family: var(--font-family-mono); font-variant-numeric: tabular-nums; color: var(--color-text-secondary); text-align: right; }
|
||
|
||
/* Live update indicator */
|
||
.live-dot {
|
||
display: inline-flex; align-items: center; gap: 6px;
|
||
font-size: 11px; color: var(--color-text-tertiary);
|
||
font-family: var(--font-family-mono); text-transform: uppercase; letter-spacing: 0.06em;
|
||
}
|
||
.live-dot__pulse {
|
||
width: 6px; height: 6px; border-radius: 50%;
|
||
background: var(--color-state-success);
|
||
box-shadow: 0 0 0 0 currentColor;
|
||
animation: pulse 1.6s infinite;
|
||
}
|
||
@keyframes pulse {
|
||
0% { box-shadow: 0 0 0 0 rgba(26,127,55,0.4); }
|
||
70% { box-shadow: 0 0 0 6px rgba(26,127,55,0); }
|
||
100% { box-shadow: 0 0 0 0 rgba(26,127,55,0); }
|
||
}
|
||
|
||
/* Critique stack */
|
||
.critiques { display: flex; flex-direction: column; gap: var(--space-3); }
|
||
.critique {
|
||
border: 1px solid var(--color-border-subtle);
|
||
border-radius: var(--radius-md);
|
||
background: var(--color-surface);
|
||
overflow: hidden;
|
||
transition: border-color 0.15s, box-shadow 0.15s;
|
||
}
|
||
.critique:hover { border-color: var(--color-border-moderate); box-shadow: var(--shadow-sm); }
|
||
.critique[data-active="true"] {
|
||
border-color: var(--color-primary-500);
|
||
box-shadow: 0 0 0 2px var(--color-primary-100);
|
||
}
|
||
.critique__head {
|
||
display: grid; grid-template-columns: auto 1fr auto;
|
||
gap: var(--space-3);
|
||
padding: 12px 14px;
|
||
align-items: center;
|
||
cursor: pointer;
|
||
}
|
||
.critique__sev {
|
||
width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0;
|
||
}
|
||
.critique[data-severity="high"] .critique__sev { background: var(--color-severity-high); }
|
||
.critique[data-severity="medium"] .critique__sev { background: var(--color-severity-medium); }
|
||
.critique[data-severity="low"] .critique__sev { background: var(--color-severity-low); }
|
||
.critique[data-severity="info"] .critique__sev { background: var(--color-state-info); }
|
||
.critique__title { font-size: var(--font-size-sm); font-weight: var(--font-weight-semibold); }
|
||
.critique__meta {
|
||
display: flex; gap: 6px; font-size: 11px;
|
||
font-family: var(--font-family-mono); color: var(--color-text-tertiary);
|
||
}
|
||
.critique__body {
|
||
padding: 0 14px 14px 30px;
|
||
display: flex; flex-direction: column; gap: 10px;
|
||
font-size: var(--font-size-sm);
|
||
line-height: 1.5;
|
||
color: var(--color-text-secondary);
|
||
}
|
||
.critique__quote {
|
||
padding: 8px 12px;
|
||
background: var(--color-bg-soft);
|
||
border-left: 2px solid var(--color-border-moderate);
|
||
border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
|
||
font-family: var(--font-family-serif);
|
||
font-size: var(--font-size-sm);
|
||
color: var(--color-text-primary);
|
||
font-style: italic;
|
||
}
|
||
.critique__suggestion {
|
||
padding: 10px 12px;
|
||
background: var(--color-severity-low-soft);
|
||
color: var(--color-severity-low-on);
|
||
border-radius: var(--radius-sm);
|
||
font-family: var(--font-family-serif);
|
||
font-size: var(--font-size-sm);
|
||
line-height: 1.5;
|
||
}
|
||
.critique__suggestion::before {
|
||
content: "→ Forslag: ";
|
||
font-family: var(--font-family-sans);
|
||
font-weight: var(--font-weight-semibold);
|
||
font-style: normal;
|
||
}
|
||
.critique__actions { display: flex; gap: 8px; padding-top: 4px; }
|
||
.critique__rule {
|
||
font-size: 11px; font-family: var(--font-family-mono);
|
||
color: var(--color-text-tertiary);
|
||
padding: 2px 6px;
|
||
background: var(--color-surface-sunken);
|
||
border-radius: var(--radius-sm);
|
||
}
|
||
|
||
/* Compare mode */
|
||
.compare-grid {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: 0;
|
||
}
|
||
.compare-col { padding: var(--space-4); }
|
||
.compare-col + .compare-col { border-left: 1px solid var(--color-border-subtle); }
|
||
.compare-col__label {
|
||
font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em;
|
||
color: var(--color-text-tertiary); margin-bottom: 8px; font-weight: var(--font-weight-semibold);
|
||
}
|
||
|
||
/* Section headers */
|
||
.h3 { font-size: var(--font-size-md); font-weight: var(--font-weight-semibold); margin: 0 0 var(--space-3); color: var(--color-text-primary); }
|
||
.h4 { font-size: var(--font-size-sm); font-weight: var(--font-weight-semibold); margin: 0 0 var(--space-2); color: var(--color-text-secondary); text-transform: uppercase; letter-spacing: 0.06em; }
|
||
|
||
/* Terminology drawer */
|
||
.term-drawer {
|
||
margin-top: var(--space-6);
|
||
padding: var(--space-5);
|
||
background: var(--color-bg-soft);
|
||
border-radius: var(--radius-md);
|
||
border: 1px solid var(--color-border-subtle);
|
||
}
|
||
.term-row { display: grid; grid-template-columns: 200px 1fr; gap: var(--space-3); padding: 8px 0; border-top: 1px dashed var(--color-border-subtle); font-size: var(--font-size-sm); }
|
||
.term-row:first-of-type { border-top: none; }
|
||
.term-row dt { font-weight: var(--font-weight-semibold); color: var(--color-text-primary); }
|
||
.term-row dd { margin: 0; color: var(--color-text-secondary); line-height: 1.5; }
|
||
|
||
/* Toggle for view modes */
|
||
.view-toggle {
|
||
display: flex; gap: 2px; padding: 3px;
|
||
background: var(--color-bg-soft); border-radius: var(--radius-md);
|
||
}
|
||
.view-toggle button {
|
||
padding: 6px 12px; font-size: 12px; font-weight: var(--font-weight-medium);
|
||
background: transparent; border: none; border-radius: var(--radius-sm);
|
||
cursor: pointer; color: var(--color-text-secondary); font-family: inherit;
|
||
}
|
||
.view-toggle button[aria-pressed="true"] {
|
||
background: var(--color-surface); color: var(--color-text-primary);
|
||
box-shadow: var(--shadow-sm);
|
||
}
|
||
|
||
/* Cohort comparison */
|
||
.cohort-grid {
|
||
display: grid; grid-template-columns: 1fr 1fr 1fr; gap: var(--space-4);
|
||
margin-top: var(--space-3);
|
||
}
|
||
.cohort-card {
|
||
padding: var(--space-4);
|
||
border: 1px solid var(--color-border-subtle);
|
||
border-radius: var(--radius-md);
|
||
background: var(--color-surface);
|
||
}
|
||
.cohort-card__head { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: var(--space-3); }
|
||
.cohort-card__name { font-weight: var(--font-weight-semibold); font-size: var(--font-size-sm); }
|
||
.cohort-card__count { font-size: 11px; color: var(--color-text-tertiary); font-family: var(--font-family-mono); }
|
||
.cohort-card__metric { display: flex; align-items: baseline; gap: 4px; margin-bottom: 8px; }
|
||
.cohort-card__metric-num { font-size: var(--font-size-2xl); font-weight: var(--font-weight-bold); font-variant-numeric: tabular-nums; letter-spacing: -0.01em; }
|
||
.cohort-card__metric-suffix { font-size: var(--font-size-sm); color: var(--color-text-tertiary); }
|
||
|
||
/* Final summary */
|
||
.final-banner {
|
||
padding: var(--space-5);
|
||
background: var(--color-severity-low-soft);
|
||
color: var(--color-severity-low-on);
|
||
border-radius: var(--radius-md);
|
||
border: 1px solid #BFDDC8;
|
||
display: grid; grid-template-columns: auto 1fr auto; gap: var(--space-5);
|
||
align-items: center;
|
||
margin-bottom: var(--space-5);
|
||
}
|
||
.final-banner__icon {
|
||
width: 44px; height: 44px; border-radius: 50%;
|
||
background: var(--color-severity-low); color: #fff;
|
||
display: flex; align-items: center; justify-content: center;
|
||
font-size: 24px; font-weight: var(--font-weight-bold);
|
||
}
|
||
|
||
@media (max-width: 1100px) {
|
||
.writer { grid-template-columns: 1fr; }
|
||
.cohort-grid { grid-template-columns: 1fr; }
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<div class="layout">
|
||
|
||
<!-- HEADER STRIP ============================================ -->
|
||
<header style="background: var(--color-surface); border-bottom: 1px solid var(--color-border-subtle); padding: 12px 0;">
|
||
<div class="container" style="display: flex; justify-content: space-between; align-items: center;">
|
||
<div style="display: flex; align-items: center; gap: var(--space-4);">
|
||
<a href="index.html" style="text-decoration: none; color: var(--color-text-tertiary); font-size: var(--font-size-sm);">← Tilbake</a>
|
||
<span style="color: var(--color-border-moderate);">/</span>
|
||
<span style="font-size: var(--font-size-sm); color: var(--color-text-secondary);">Playground / Scenarios / OKR live writer</span>
|
||
</div>
|
||
<div style="display: flex; gap: var(--space-3); align-items: center;">
|
||
<span class="live-dot"><span class="live-dot__pulse"></span> Live · 4 forfattere</span>
|
||
<button class="btn btn--ghost" id="theme-toggle" aria-pressed="false">Mørk</button>
|
||
</div>
|
||
</div>
|
||
</header>
|
||
|
||
<main class="container page">
|
||
|
||
<!-- PAGE HEADER -->
|
||
<div class="page__header">
|
||
<div class="page__title">
|
||
<span class="page__eyebrow">OKR live-writer · Bærum kommune</span>
|
||
<h1 style="margin: 0; font-size: var(--font-size-3xl);">Tjenesteutvikling — T2 2026</h1>
|
||
<div class="page__meta">
|
||
<span class="page__meta-item"><span class="page__meta-label">Avd.</span> Innbyggertjenester</span>
|
||
<span class="page__meta-item"><span class="page__meta-label">Eier</span> Anne Hovde</span>
|
||
<span class="page__meta-item"><span class="page__meta-label">Frist</span> 15. mai 2026</span>
|
||
<span class="page__meta-item"><span class="page__meta-label">Lagret</span> 12 sek siden</span>
|
||
</div>
|
||
</div>
|
||
<div style="display: flex; gap: var(--space-2);">
|
||
<button class="btn btn--ghost">Versjoner</button>
|
||
<button class="btn btn--secondary">Eksporter PDF</button>
|
||
<button class="btn btn--primary">Send til godkjenning</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- SCORE STRIP -->
|
||
<div class="score-strip">
|
||
<div class="score-strip__num" id="score-num">62<small>/100</small></div>
|
||
<div class="score-strip__bars">
|
||
<div class="score-strip__bar">
|
||
<span class="score-strip__bar-label">Måling</span>
|
||
<div class="score-strip__bar-track"><div class="score-strip__bar-fill" style="width: 40%; background: var(--color-severity-medium);"></div></div>
|
||
<span class="score-strip__bar-num">4/10</span>
|
||
</div>
|
||
<div class="score-strip__bar">
|
||
<span class="score-strip__bar-label">Spesifikt</span>
|
||
<div class="score-strip__bar-track"><div class="score-strip__bar-fill" style="width: 60%; background: var(--color-severity-high);"></div></div>
|
||
<span class="score-strip__bar-num">6/10</span>
|
||
</div>
|
||
<div class="score-strip__bar">
|
||
<span class="score-strip__bar-label">Ambisjon</span>
|
||
<div class="score-strip__bar-track"><div class="score-strip__bar-fill" style="width: 70%; background: var(--color-severity-low);"></div></div>
|
||
<span class="score-strip__bar-num">7/10</span>
|
||
</div>
|
||
<div class="score-strip__bar">
|
||
<span class="score-strip__bar-label">Påvirkbart</span>
|
||
<div class="score-strip__bar-track"><div class="score-strip__bar-fill" style="width: 80%; background: var(--color-severity-low);"></div></div>
|
||
<span class="score-strip__bar-num">8/10</span>
|
||
</div>
|
||
</div>
|
||
<div style="display: flex; flex-direction: column; align-items: flex-end; gap: 4px;">
|
||
<span class="badge" style="background: var(--color-severity-medium-soft); color: var(--color-severity-medium-on);">Trenger arbeid</span>
|
||
<span style="font-size: 11px; color: var(--color-text-tertiary); font-family: var(--font-family-mono);">v0.4 · oppdatert kontinuerlig</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- VIEW TOGGLE -->
|
||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: var(--space-4);">
|
||
<div class="view-toggle" role="tablist">
|
||
<button role="tab" aria-pressed="true" data-view="writer">Skriv (live-kritikk)</button>
|
||
<button role="tab" aria-pressed="false" data-view="rewrite">Sammenlign (før / etter)</button>
|
||
<button role="tab" aria-pressed="false" data-view="cohort">Kohort (avd.-gj.snitt)</button>
|
||
<button role="tab" aria-pressed="false" data-view="final">Endelig versjon</button>
|
||
</div>
|
||
<div style="font-size: 11px; color: var(--color-text-tertiary); font-family: var(--font-family-mono);">
|
||
Modell kjører lokalt · ingen data forlater Bærum nett
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ========================================================= -->
|
||
<!-- VIEW 1: WRITER (live critique) -->
|
||
<!-- ========================================================= -->
|
||
<section class="view" data-view-content="writer">
|
||
<div class="writer">
|
||
|
||
<!-- LEFT: editor -->
|
||
<div class="pane">
|
||
<div class="pane__head">
|
||
<h2 class="pane__title">
|
||
<span class="pane__title-eyebrow">Utkast</span>
|
||
Tjenesteutvikling — utkast 0.4
|
||
</h2>
|
||
<span class="live-dot"><span class="live-dot__pulse"></span> Auto-kritikk</span>
|
||
</div>
|
||
<div class="pane__body">
|
||
<div class="editor" id="editor">
|
||
<p class="objective">
|
||
<span class="hl" data-issue="vague-verb" data-cid="c1">Forbedre</span>
|
||
digitale tjenester for innbyggerne i Bærum kommune slik at de
|
||
<span class="hl" data-issue="vague-verb" data-cid="c2">opplever bedre service</span>.
|
||
</p>
|
||
|
||
<h2 style="font-size: var(--font-size-sm); color: var(--color-text-tertiary); text-transform: uppercase; letter-spacing: 0.06em;">Nøkkelresultater</h2>
|
||
|
||
<div class="kr">
|
||
<span class="kr-label">KR1</span>
|
||
<p class="kr-text">
|
||
Øke andelen henvendelser løst i selvbetjeningsløsningen
|
||
<span class="hl" data-issue="missing-baseline" data-cid="c3">betydelig</span>
|
||
sammenlignet med i fjor.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="kr">
|
||
<span class="kr-label">KR2</span>
|
||
<p class="kr-text">
|
||
<span class="hl" data-issue="activity" data-cid="c4">Lansere ny chatbot på kommune.no</span>
|
||
innen utgangen av tertialet.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="kr">
|
||
<span class="kr-label">KR3</span>
|
||
<p class="kr-text">
|
||
Redusere ventetid for byggesakshenvendelser
|
||
<span class="hl" data-issue="no-metric" data-cid="c5">vesentlig</span>.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="kr">
|
||
<span class="kr-label">KR4</span>
|
||
<p class="kr-text">
|
||
Innbyggertilfredshet på 4,2 av 5 målt i T2-undersøkelsen
|
||
<span class="hl" data-issue="no-deadline" data-cid="c6"></span>.
|
||
</p>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
<div style="padding: 10px 16px; background: var(--color-bg-soft); border-top: 1px solid var(--color-border-subtle); display: flex; justify-content: space-between; align-items: center; font-size: 12px; color: var(--color-text-tertiary); font-family: var(--font-family-mono);">
|
||
<span>248 ord · 1 mål · 4 nøkkelresultater</span>
|
||
<span>Sist endret 14:23 · Anne H.</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- RIGHT: critique panel -->
|
||
<div class="pane">
|
||
<div class="pane__head">
|
||
<h2 class="pane__title">
|
||
<span class="pane__title-eyebrow">Kritikk</span>
|
||
6 funn
|
||
</h2>
|
||
<span class="badge badge--soft">Regelsett: kommunal-okr-v2</span>
|
||
</div>
|
||
<div class="pane__body" style="padding: var(--space-3);">
|
||
<div class="critiques">
|
||
|
||
<article class="critique" data-severity="high" data-cid="c4" data-active="true">
|
||
<header class="critique__head">
|
||
<span class="critique__sev"></span>
|
||
<div>
|
||
<div class="critique__title">Aktivitet maskert som nøkkelresultat</div>
|
||
<div class="critique__meta"><span>KR2</span> · <span class="critique__rule">activity-not-outcome</span></div>
|
||
</div>
|
||
<span style="font-size: 18px; color: var(--color-text-tertiary);">▾</span>
|
||
</header>
|
||
<div class="critique__body">
|
||
<div class="critique__quote">«Lansere ny chatbot på kommune.no»</div>
|
||
<p>Et nøkkelresultat skal beskrive en <strong>endring i verden</strong>, ikke en aktivitet eller en leveranse. Lansering er en milepæl — det er en input, ikke et utfall.</p>
|
||
<div class="critique__suggestion">«Andelen innbyggere som får løst sitt spørsmål i første henvendelse økes fra 38 % (T1 2026) til 55 % innen 31. august 2026.»</div>
|
||
<div class="critique__actions">
|
||
<button class="btn btn--primary btn--sm">Bruk forslag</button>
|
||
<button class="btn btn--ghost btn--sm">Skjul</button>
|
||
</div>
|
||
</div>
|
||
</article>
|
||
|
||
<article class="critique" data-severity="high" data-cid="c5">
|
||
<header class="critique__head">
|
||
<span class="critique__sev"></span>
|
||
<div>
|
||
<div class="critique__title">Ingen målbar verdi</div>
|
||
<div class="critique__meta"><span>KR3</span> · <span class="critique__rule">no-metric</span></div>
|
||
</div>
|
||
<span style="font-size: 18px; color: var(--color-text-tertiary);">▾</span>
|
||
</header>
|
||
<div class="critique__body">
|
||
<div class="critique__quote">«Redusere ventetid … vesentlig»</div>
|
||
<p>«Vesentlig» kan ikke etterprøves. KR-et trenger en tallverdi (i dager / timer) og et utgangspunkt fra T1.</p>
|
||
<div class="critique__suggestion">«Median saksbehandlingstid for byggesak reduseres fra 47 dager (T1 2026) til 30 dager innen 31. august 2026.»</div>
|
||
</div>
|
||
</article>
|
||
|
||
<article class="critique" data-severity="medium" data-cid="c3">
|
||
<header class="critique__head">
|
||
<span class="critique__sev"></span>
|
||
<div>
|
||
<div class="critique__title">Mangler utgangspunkt</div>
|
||
<div class="critique__meta"><span>KR1</span> · <span class="critique__rule">missing-baseline</span></div>
|
||
</div>
|
||
<span style="font-size: 18px; color: var(--color-text-tertiary);">▾</span>
|
||
</header>
|
||
<div class="critique__body">
|
||
<div class="critique__quote">«… betydelig sammenlignet med i fjor»</div>
|
||
<p>«Sammenlignet med i fjor» er en relativ måling uten basisverdi. T1-tallet for selvbetjeningsandel finnes i Tableau-sett <span style="font-family: var(--font-family-mono); font-size: 12px;">tjeneste-kpi-2026q1</span>.</p>
|
||
<div class="critique__suggestion">«Andelen henvendelser fullført i selvbetjeningsløsningen økes fra 41 % (T1 2026) til 60 % innen 31. august 2026.»</div>
|
||
</div>
|
||
</article>
|
||
|
||
<article class="critique" data-severity="medium" data-cid="c1">
|
||
<header class="critique__head">
|
||
<span class="critique__sev"></span>
|
||
<div>
|
||
<div class="critique__title">Vagt verb i Objective</div>
|
||
<div class="critique__meta"><span>O</span> · <span class="critique__rule">vague-verb</span></div>
|
||
</div>
|
||
<span style="font-size: 18px; color: var(--color-text-tertiary);">▾</span>
|
||
</header>
|
||
<div class="critique__body">
|
||
<div class="critique__quote">«Forbedre digitale tjenester …»</div>
|
||
<p>«Forbedre» kan bety nesten hva som helst. Et godt Objective er kvalitativt og inspirerende, men det skal også gi retning. Hva betyr «bedre» for en innbygger her?</p>
|
||
<div class="critique__suggestion">«Innbyggere i Bærum får svar på sine kommunale spørsmål i løpet av samme dag — uten å måtte ringe.»</div>
|
||
</div>
|
||
</article>
|
||
|
||
<article class="critique" data-severity="medium" data-cid="c6">
|
||
<header class="critique__head">
|
||
<span class="critique__sev"></span>
|
||
<div>
|
||
<div class="critique__title">Mangler tidsfrist</div>
|
||
<div class="critique__meta"><span>KR4</span> · <span class="critique__rule">no-deadline</span></div>
|
||
</div>
|
||
<span style="font-size: 18px; color: var(--color-text-tertiary);">▾</span>
|
||
</header>
|
||
<div class="critique__body">
|
||
<p>KR-et nevner T2-undersøkelsen, men ikke når den gjennomføres eller når resultatet skal foreligge.</p>
|
||
<div class="critique__suggestion">«… målt i T2-undersøkelsen som gjennomføres uke 33-35 og rapporteres innen 15. september 2026.»</div>
|
||
</div>
|
||
</article>
|
||
|
||
<article class="critique" data-severity="info">
|
||
<header class="critique__head">
|
||
<span class="critique__sev"></span>
|
||
<div>
|
||
<div class="critique__title">Hint: Strekk-mål?</div>
|
||
<div class="critique__meta">Hele settet · <span class="critique__rule">stretch-suggestion</span></div>
|
||
</div>
|
||
<span style="font-size: 18px; color: var(--color-text-tertiary);">▾</span>
|
||
</header>
|
||
<div class="critique__body">
|
||
<p>Tre av fire KR-er ligger under 1,5× nåværende baseline når du har lagt inn tall. OKR fungerer best når 60–70 % oppnåelse oppleves som godt arbeid. Vurder strekk på KR1.</p>
|
||
</div>
|
||
</article>
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div><!-- /writer -->
|
||
|
||
<!-- TERMINOLOGY -->
|
||
<div class="term-drawer">
|
||
<h3 class="h3" style="margin-bottom: var(--space-3);">Bærum-spesifikk OKR-ordliste</h3>
|
||
<p style="font-size: var(--font-size-sm); color: var(--color-text-secondary); margin-bottom: var(--space-4);">Plugin-en lærte disse begrepene fra Bærums egen styringspraksis. Andre kommuner forker pluginen og fyller på sine egne.</p>
|
||
<dl style="margin: 0;">
|
||
<div class="term-row">
|
||
<dt>Tertial</dt>
|
||
<dd>4-måneders styringsperiode (T1: jan-apr, T2: mai-aug, T3: sep-des). Erstatter «kvartal» i Bærums tekstmaler.</dd>
|
||
</div>
|
||
<div class="term-row">
|
||
<dt>Selvbetjeningsandel</dt>
|
||
<dd>KPI definert som henvendelser fullført uten saksbehandler-inngripen, kilde: <span style="font-family: var(--font-family-mono); font-size: 12px;">tjeneste-kpi-2026q1</span>.</dd>
|
||
</div>
|
||
<div class="term-row">
|
||
<dt>Innbyggertilfredshet</dt>
|
||
<dd>5-punkts skala fra årlig undersøkelse. Kommunestyrets mål: ≥ 4,0 i alle avdelinger innen 2027.</dd>
|
||
</div>
|
||
<div class="term-row">
|
||
<dt>Strekk-mål</dt>
|
||
<dd>Bærums interne term for ambisiøs verdi (mål 70 %), brukt sammen med «forventet verdi» (mål 90 %).</dd>
|
||
</div>
|
||
</dl>
|
||
</div>
|
||
|
||
</section><!-- /view writer -->
|
||
|
||
<!-- ========================================================= -->
|
||
<!-- VIEW 2: REWRITE (before/after) -->
|
||
<!-- ========================================================= -->
|
||
<section class="view" data-view-content="rewrite" style="display: none;">
|
||
|
||
<h3 class="h3">Side ved side: utkast 0.4 → forslag</h3>
|
||
<p style="color: var(--color-text-secondary); font-size: var(--font-size-sm); margin-bottom: var(--space-4);">Plugin-ens forslag bruker baseline-tall den hentet fra Bærums KPI-katalog. Du kan godta hver endring enkeltvis.</p>
|
||
|
||
<div class="diff" style="background: var(--color-surface);">
|
||
<div class="diff__summary">
|
||
<div class="diff__summary-item"><span class="diff__summary-count" style="color: var(--color-severity-critical);">−5</span><span>fjernet</span></div>
|
||
<div class="diff__summary-item"><span class="diff__summary-count" style="color: var(--color-severity-low);">+5</span><span>lagt til</span></div>
|
||
<div class="diff__summary-item"><span class="diff__summary-count">9</span><span>endringer</span></div>
|
||
</div>
|
||
|
||
<div class="diff__row">
|
||
<div class="diff__cell diff__cell--removed">Forbedre digitale tjenester for innbyggerne i Bærum kommune slik at de opplever bedre service.</div>
|
||
<div class="diff__cell diff__cell--added">Innbyggere i Bærum får svar på sine kommunale spørsmål i løpet av samme dag — uten å måtte ringe.</div>
|
||
</div>
|
||
<div class="diff__row">
|
||
<div class="diff__cell diff__cell--removed">KR1: Øke andelen henvendelser løst i selvbetjeningsløsningen betydelig sammenlignet med i fjor.</div>
|
||
<div class="diff__cell diff__cell--added">KR1: Andelen henvendelser fullført i selvbetjeningsløsningen økes fra 41 % (T1 2026) til 60 % innen 31. august 2026.</div>
|
||
</div>
|
||
<div class="diff__row">
|
||
<div class="diff__cell diff__cell--removed">KR2: Lansere ny chatbot på kommune.no innen utgangen av tertialet.</div>
|
||
<div class="diff__cell diff__cell--added">KR2: Andelen innbyggere som får løst sitt spørsmål i første henvendelse økes fra 38 % (T1 2026) til 55 % innen 31. august 2026.</div>
|
||
</div>
|
||
<div class="diff__row">
|
||
<div class="diff__cell diff__cell--removed">KR3: Redusere ventetid for byggesakshenvendelser vesentlig.</div>
|
||
<div class="diff__cell diff__cell--added">KR3: Median saksbehandlingstid for byggesak reduseres fra 47 dager (T1 2026) til 30 dager innen 31. august 2026.</div>
|
||
</div>
|
||
<div class="diff__row">
|
||
<div class="diff__cell diff__cell--removed">KR4: Innbyggertilfredshet på 4,2 av 5 målt i T2-undersøkelsen.</div>
|
||
<div class="diff__cell diff__cell--added">KR4: Innbyggertilfredshet på 4,2 av 5 målt i T2-undersøkelsen (uke 33-35), rapportert innen 15. september 2026.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="display: flex; gap: var(--space-3); justify-content: flex-end; margin-top: var(--space-4);">
|
||
<button class="btn btn--ghost">Avvis alle</button>
|
||
<button class="btn btn--secondary">Aksepter én og én</button>
|
||
<button class="btn btn--primary">Aksepter alle</button>
|
||
</div>
|
||
|
||
</section>
|
||
|
||
<!-- ========================================================= -->
|
||
<!-- VIEW 3: COHORT (anonymous benchmarking) -->
|
||
<!-- ========================================================= -->
|
||
<section class="view" data-view-content="cohort" style="display: none;">
|
||
|
||
<h3 class="h3">Hvordan du ligger an mot resten av Bærum</h3>
|
||
<p style="color: var(--color-text-secondary); font-size: var(--font-size-sm); margin-bottom: var(--space-4); max-width: var(--measure);">
|
||
Anonymisert sammenligning på tvers av avdelinger som bruker samme plugin. Tall hentes lokalt fra OKR-systemet — ingen tekst, kun aggregerte score.
|
||
</p>
|
||
|
||
<div class="cohort-grid">
|
||
<div class="cohort-card">
|
||
<div class="cohort-card__head">
|
||
<span class="cohort-card__name">Ditt sett</span>
|
||
<span class="cohort-card__count">Innbyggertjenester</span>
|
||
</div>
|
||
<div class="cohort-card__metric">
|
||
<span class="cohort-card__metric-num">62</span>
|
||
<span class="cohort-card__metric-suffix">/100</span>
|
||
</div>
|
||
<div style="font-size: 12px; color: var(--color-text-tertiary);">6 åpne funn · 2 høy alvorlighet</div>
|
||
</div>
|
||
<div class="cohort-card">
|
||
<div class="cohort-card__head">
|
||
<span class="cohort-card__name">Avd.-median</span>
|
||
<span class="cohort-card__count">14 sett</span>
|
||
</div>
|
||
<div class="cohort-card__metric">
|
||
<span class="cohort-card__metric-num">71</span>
|
||
<span class="cohort-card__metric-suffix">/100</span>
|
||
</div>
|
||
<div style="font-size: 12px; color: var(--color-text-tertiary);">P25: 58 · P75: 84</div>
|
||
</div>
|
||
<div class="cohort-card">
|
||
<div class="cohort-card__head">
|
||
<span class="cohort-card__name">Kommune-median</span>
|
||
<span class="cohort-card__count">87 sett · alle avd.</span>
|
||
</div>
|
||
<div class="cohort-card__metric">
|
||
<span class="cohort-card__metric-num">68</span>
|
||
<span class="cohort-card__metric-suffix">/100</span>
|
||
</div>
|
||
<div style="font-size: 12px; color: var(--color-text-tertiary);">Beste avd.: Eiendom · 81</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="margin-top: var(--space-6);">
|
||
<h4 class="h4">Hyppigste funn på tvers av Bærum (T2 så langt)</h4>
|
||
<div class="distribution">
|
||
<div class="distribution__row">
|
||
<span class="distribution__label">activity-not-outcome</span>
|
||
<div class="distribution__track">
|
||
<div class="distribution__band" style="left: 18%; right: 28%;"></div>
|
||
<div class="distribution__median" style="left: 41%;"><span class="distribution__median-label">41 % av sett</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="distribution__row">
|
||
<span class="distribution__label">no-metric</span>
|
||
<div class="distribution__track">
|
||
<div class="distribution__band" style="left: 12%; right: 42%;"></div>
|
||
<div class="distribution__median" style="left: 33%;"><span class="distribution__median-label">33 %</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="distribution__row">
|
||
<span class="distribution__label">missing-baseline</span>
|
||
<div class="distribution__track">
|
||
<div class="distribution__band" style="left: 22%; right: 22%;"></div>
|
||
<div class="distribution__median" style="left: 51%;"><span class="distribution__median-label">51 %</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="distribution__row">
|
||
<span class="distribution__label">vague-verb</span>
|
||
<div class="distribution__track">
|
||
<div class="distribution__band" style="left: 30%; right: 18%;"></div>
|
||
<div class="distribution__median" style="left: 60%;"><span class="distribution__median-label">60 %</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="distribution__row">
|
||
<span class="distribution__label">no-deadline</span>
|
||
<div class="distribution__track">
|
||
<div class="distribution__band" style="left: 8%; right: 56%;"></div>
|
||
<div class="distribution__median" style="left: 24%;"><span class="distribution__median-label">24 %</span></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p style="font-size: 12px; color: var(--color-text-tertiary); margin-top: var(--space-3); font-family: var(--font-family-mono);">
|
||
Bånd = P25–P75 på tvers av avd. · linje = median andel sett som har minst ett slikt funn
|
||
</p>
|
||
</div>
|
||
|
||
</section>
|
||
|
||
<!-- ========================================================= -->
|
||
<!-- VIEW 4: FINAL -->
|
||
<!-- ========================================================= -->
|
||
<section class="view" data-view-content="final" style="display: none;">
|
||
|
||
<div class="final-banner">
|
||
<div class="final-banner__icon">✓</div>
|
||
<div>
|
||
<div style="font-size: var(--font-size-lg); font-weight: var(--font-weight-semibold); margin-bottom: 2px;">Klar for godkjenning · score 91/100</div>
|
||
<div style="font-size: var(--font-size-sm); opacity: 0.9;">0 høye funn · 1 informasjonshint · alle KR har baseline, mål og frist</div>
|
||
</div>
|
||
<button class="btn btn--primary">Send til virksomhetsleder</button>
|
||
</div>
|
||
|
||
<article style="background: var(--color-surface); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-md); padding: var(--space-8); max-width: 800px;">
|
||
<div style="font-size: 11px; color: var(--color-text-tertiary); text-transform: uppercase; letter-spacing: 0.08em; margin-bottom: var(--space-2);">Bærum kommune · Innbyggertjenester · T2 2026 · v1.0</div>
|
||
<h2 style="font-family: var(--font-family-serif); font-size: 28px; line-height: 1.3; margin: 0 0 var(--space-6); color: var(--color-text-primary);">
|
||
Innbyggere i Bærum får svar på sine kommunale spørsmål i løpet av samme dag — uten å måtte ringe.
|
||
</h2>
|
||
|
||
<h3 class="h4" style="margin-bottom: var(--space-4);">Nøkkelresultater</h3>
|
||
|
||
<div style="display: flex; flex-direction: column; gap: var(--space-3);">
|
||
<div style="padding: var(--space-4); background: var(--color-bg-soft); border-left: 3px solid var(--color-scope-okr); border-radius: 0 var(--radius-sm) var(--radius-sm) 0;">
|
||
<div style="font-family: var(--font-family-mono); font-size: 11px; color: var(--color-scope-okr); font-weight: var(--font-weight-semibold); margin-bottom: 4px; letter-spacing: 0.06em;">KR1</div>
|
||
<div style="font-family: var(--font-family-serif); font-size: 17px; line-height: 1.5;">Andelen henvendelser fullført i selvbetjeningsløsningen økes fra <strong>41 %</strong> (T1 2026) til <strong>60 %</strong> innen 31. august 2026.</div>
|
||
</div>
|
||
<div style="padding: var(--space-4); background: var(--color-bg-soft); border-left: 3px solid var(--color-scope-okr); border-radius: 0 var(--radius-sm) var(--radius-sm) 0;">
|
||
<div style="font-family: var(--font-family-mono); font-size: 11px; color: var(--color-scope-okr); font-weight: var(--font-weight-semibold); margin-bottom: 4px; letter-spacing: 0.06em;">KR2</div>
|
||
<div style="font-family: var(--font-family-serif); font-size: 17px; line-height: 1.5;">Andelen innbyggere som får løst sitt spørsmål i første henvendelse økes fra <strong>38 %</strong> (T1 2026) til <strong>55 %</strong> innen 31. august 2026.</div>
|
||
</div>
|
||
<div style="padding: var(--space-4); background: var(--color-bg-soft); border-left: 3px solid var(--color-scope-okr); border-radius: 0 var(--radius-sm) var(--radius-sm) 0;">
|
||
<div style="font-family: var(--font-family-mono); font-size: 11px; color: var(--color-scope-okr); font-weight: var(--font-weight-semibold); margin-bottom: 4px; letter-spacing: 0.06em;">KR3</div>
|
||
<div style="font-family: var(--font-family-serif); font-size: 17px; line-height: 1.5;">Median saksbehandlingstid for byggesak reduseres fra <strong>47 dager</strong> (T1 2026) til <strong>30 dager</strong> innen 31. august 2026.</div>
|
||
</div>
|
||
<div style="padding: var(--space-4); background: var(--color-bg-soft); border-left: 3px solid var(--color-scope-okr); border-radius: 0 var(--radius-sm) var(--radius-sm) 0;">
|
||
<div style="font-family: var(--font-family-mono); font-size: 11px; color: var(--color-scope-okr); font-weight: var(--font-weight-semibold); margin-bottom: 4px; letter-spacing: 0.06em;">KR4</div>
|
||
<div style="font-family: var(--font-family-serif); font-size: 17px; line-height: 1.5;">Innbyggertilfredshet på <strong>4,2 av 5</strong> målt i T2-undersøkelsen (uke 33–35), rapportert innen 15. september 2026.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="margin-top: var(--space-8); padding-top: var(--space-5); border-top: 1px solid var(--color-border-subtle); display: flex; justify-content: space-between; font-size: 12px; color: var(--color-text-tertiary); font-family: var(--font-family-mono);">
|
||
<span>Eier: Anne Hovde · Innbyggertjenester</span>
|
||
<span>Generert med okr-writer-baerum v2.3 · 12 reviderte uttkast</span>
|
||
</div>
|
||
</article>
|
||
|
||
</section>
|
||
|
||
</main>
|
||
</div>
|
||
|
||
<script>
|
||
// Theme toggle
|
||
const themeBtn = document.getElementById('theme-toggle');
|
||
const setTheme = (t) => {
|
||
document.documentElement.setAttribute('data-theme', t);
|
||
themeBtn.textContent = t === 'dark' ? 'Lys' : 'Mørk';
|
||
themeBtn.setAttribute('aria-pressed', t === 'dark' ? 'true' : 'false');
|
||
try { localStorage.setItem('pg-theme', t); } catch(e) {}
|
||
};
|
||
setTheme(localStorage.getItem('pg-theme') || 'light');
|
||
themeBtn.addEventListener('click', () => {
|
||
setTheme(document.documentElement.getAttribute('data-theme') === 'dark' ? 'light' : 'dark');
|
||
});
|
||
|
||
// View toggle
|
||
const views = document.querySelectorAll('[data-view-content]');
|
||
document.querySelectorAll('.view-toggle button').forEach(btn => {
|
||
btn.addEventListener('click', () => {
|
||
const v = btn.dataset.view;
|
||
document.querySelectorAll('.view-toggle button').forEach(b => b.setAttribute('aria-pressed', b === btn ? 'true' : 'false'));
|
||
views.forEach(s => { s.style.display = s.dataset.viewContent === v ? '' : 'none'; });
|
||
try { history.replaceState(null, '', '#' + v); } catch(e) {}
|
||
});
|
||
});
|
||
// initial from hash
|
||
const initialView = (location.hash || '').replace('#','') || 'writer';
|
||
const tab = document.querySelector(`[data-view="${initialView}"]`);
|
||
if (tab) tab.click();
|
||
|
||
// Critique <-> editor highlighting
|
||
const editor = document.getElementById('editor');
|
||
document.querySelectorAll('.critique').forEach(c => {
|
||
c.querySelector('.critique__head').addEventListener('click', () => {
|
||
document.querySelectorAll('.critique').forEach(x => x.removeAttribute('data-active'));
|
||
c.setAttribute('data-active', 'true');
|
||
const cid = c.dataset.cid;
|
||
if (cid) {
|
||
const target = editor.querySelector(`[data-cid="${cid}"]`);
|
||
if (target) {
|
||
target.style.transition = 'background-color 0.6s';
|
||
target.style.backgroundColor = 'rgba(0, 98, 186, 0.18)';
|
||
setTimeout(() => { target.style.backgroundColor = ''; }, 1400);
|
||
}
|
||
}
|
||
});
|
||
});
|
||
|
||
// Hover linking from editor to critique
|
||
editor.querySelectorAll('.hl').forEach(hl => {
|
||
hl.addEventListener('mouseenter', () => {
|
||
const cid = hl.dataset.cid;
|
||
const c = document.querySelector(`.critique[data-cid="${cid}"]`);
|
||
if (c) c.style.outline = '2px solid var(--color-primary-300)';
|
||
});
|
||
hl.addEventListener('mouseleave', () => {
|
||
const cid = hl.dataset.cid;
|
||
const c = document.querySelector(`.critique[data-cid="${cid}"]`);
|
||
if (c) c.style.outline = '';
|
||
});
|
||
});
|
||
</script>
|
||
|
||
</body>
|
||
</html>
|