/* global React */ const { useState, useEffect, useRef, useMemo } = React; /* ─── Stamp ─────────────────────────────────────────────────────── */ function Stamp({ children, ink }) { return {children}; } /* ─── Art-chip (instrument badge) ───────────────────────────────── */ function ArtChip({ code, tone = "red", title }) { const cls = "art-chip" + (tone === "blue" ? " is-blue" : tone === "amber" ? " is-amber" : ""); return {code}; } /* ─── Redact span ───────────────────────────────────────────────── */ function Redact({ children, len }) { // render fixed-width blocks if `len` is passed; otherwise show children styled as bar const text = len ? "█".repeat(len) : (children || "████"); return {text}; } /* ─── Cite chip (richer) ─────────────────────────────────────────── */ function CiteChip({ n, active, onClick }) { return ( {n} ); } /* ─── Topbar with case-number ───────────────────────────────────── */ function Topbar({ caseNo, status }) { return (

Do Better Norge · tools.dobetternorge.no

Legal Tools · Case Workbench

{caseNo} · session in memory · nothing stored
ECHR Art. 8 monitoring {status}
); } /* ─── Manifesto strip — replaces vanilla disclaimer with a headline + stats */ function Manifesto({ headline, stats, intensity }) { return (

{headline.eyebrow}

{headline.title}

{headline.sub}

{stats.echrViolations}
ECHR violations since 2015
{stats.echrLossRate}%
cases lost 2017–22
{stats.tribunalDecisions.toLocaleString()}
tribunal decisions analysed
{stats.pendingStrasbourg}+
pending Strasbourg
); } /* ─── Disclaimer (kept, but reskinned amber) ────────────────────── */ function Disclaimer() { return (
Notice.  Legal information and preparation support, not final legal advice. Pasted text is processed in memory by default under ECHR Art. 8 and Norwegian Personopplysningsloven principles.
); } /* ─── Tool rail (themed) ────────────────────────────────────────── */ const TOOLS = [ { slug: "ask", label: "Ask", sub: "source-grounded", tag: "Art. 8" }, { slug: "search", label: "Search", sub: "lovdata + echr", tag: "1.7K" }, { slug: "advocate", label: "Advocate", sub: "take a side", tag: "★" }, { slug: "redact", label: "Redact", sub: "in-memory only", tag: "GDPR" }, { slug: "timeline", label: "Timeline", sub: "events extracted", tag: "12 min" }, { slug: "cases", label: "Casebook", sub: "23 violations", tag: "23" }, { slug: "voices", label: "Voices", sub: "verified accounts", tag: "4" }, ]; function ToolRail({ active, onSelect }) { return ( ); } /* ─── Reasoning panel (Evidence Trail) ──────────────────────────── */ const TRACE_WAITING = [ { label: "Waiting for query", detail: "Open a tool on the left. The evidence trail is built as the answer is generated.", status: "waiting" }, ]; function TraceList({ steps }) { return (
    {steps.map((s, i) => (
  1. {s.label}

    {s.detail}

  2. ))}
); } function ReasoningPanel({ steps, caseNo, instrument }) { return ( ); } /* ─── Footer strip ──────────────────────────────────────────────── */ function FootStrip() { return (
Do Better Norge · independent advocacy · founded by affected parents Powered by CaveauAI · Blue Note Logic · in-memory RAG · no telemetry
); } /* ─── Run helper (timed promise sequence for fake tool runs) ────── */ function useRunSequence() { const timers = useRef([]); useEffect(() => () => timers.current.forEach(clearTimeout), []); function clear() { timers.current.forEach(clearTimeout); timers.current = []; } function run(sequence, onStep, onDone) { clear(); let cum = 0; sequence.forEach((entry, idx) => { cum += entry.delay; const t = setTimeout(() => { onStep(entry.step, idx, idx === sequence.length - 1); if (idx === sequence.length - 1) onDone && onDone(); }, cum); timers.current.push(t); }); } return { run, clear }; } /* ─── Headline labeller / instrument helper ─────────────────────── */ function lookupInstrument(code) { const m = (window.DBN_DATA.instruments || []).find(i => i.code === code); return m ? m.full : code; } /* ─── Expose ────────────────────────────────────────────────────── */ Object.assign(window, { Stamp, ArtChip, Redact, CiteChip, Topbar, Manifesto, Disclaimer, ToolRail, TOOLS, ReasoningPanel, TraceList, TRACE_WAITING, FootStrip, useRunSequence, lookupInstrument, });