Add 3 public Korrespond documentation pages with AI hero images

- korrespond-about.php: marketing/hype page with hero image, features,
  3-step pipeline, screenshot gallery, dbn-legal-agent LLM spotlight,
  authority coverage grid, and CTA strip
- korrespond-guide.php: step-by-step user guide covering mode selection,
  recipient body presets, output types, tone, all form fields, clarify
  gate, output columns, and Refine pass
- korrespond-tech.php: technical showcase — Hard-RAG pipeline diagram,
  corpus stats, CITE:N verification system, fine-tuned model details,
  formal citation style guide, privacy section
- 5 UI screenshots + 3 AI-generated hero images in assets/images/korrespond/
- korrespond.php: add "About · User guide · How it works" inline links
- preview.php: add korrespond to localizedContent (en+no) and samples;
  render doc-page links in preview CTA section for korrespond slug
- tools.css: +600 lines .kdoc-* CSS (hero, features, pipeline, guide
  steps, tech diagrams, finetune block, privacy block, stat cards)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-19 12:49:38 +02:00
parent 28932297b3
commit 7c4b161f04
14 changed files with 1884 additions and 0 deletions
+776
View File
@@ -7177,3 +7177,779 @@ body.lt-landing {
border-top: 1px solid rgba(0, 32, 91, 0.18); border-top: 1px solid rgba(0, 32, 91, 0.18);
} }
/* ── korr-doc-links (in-tool breadcrumb links) ───────────────────────── */
.korr-doc-links {
display: flex;
align-items: center;
gap: 8px;
font-size: 0.8rem;
color: var(--dbn-ink, #16130f);
opacity: 0.6;
margin-bottom: 18px;
}
.korr-doc-links a {
color: var(--dbn-blue, #00205b);
text-decoration: none;
}
.korr-doc-links a:hover {
text-decoration: underline;
}
/* ═══════════════════════════════════════════════════════════════════════
KDOC — Public documentation pages (korrespond-about / guide / tech)
═══════════════════════════════════════════════════════════════════════ */
/* ── Shared page wrapper ─────────────────────────────────────────────── */
.kdoc-page {
background: var(--dbn-paper, #f6f2ea);
color: var(--dbn-ink, #16130f);
min-height: 100vh;
font-family: 'IBM Plex Sans', sans-serif;
}
/* ── Nav breadcrumb row ──────────────────────────────────────────────── */
.kdoc-breadcrumb {
max-width: 1100px;
margin: 0 auto;
padding: 12px 2rem;
font-size: 0.82rem;
color: var(--dbn-ink);
opacity: 0.7;
}
.kdoc-breadcrumb a {
color: var(--dbn-blue, #00205b);
text-decoration: none;
}
.kdoc-breadcrumb a:hover { text-decoration: underline; }
/* ── Hero ─────────────────────────────────────────────────────────────── */
.kdoc-hero {
background: var(--dbn-blue, #00205b);
color: #fff;
padding: clamp(3rem, 8vw, 6rem) 2rem clamp(3rem, 6vw, 5rem);
text-align: center;
}
.kdoc-hero__inner {
max-width: 860px;
margin: 0 auto;
}
.kdoc-hero__kicker {
font-size: 0.78rem;
letter-spacing: 0.1em;
text-transform: uppercase;
opacity: 0.75;
margin-bottom: 1rem;
}
.kdoc-hero__title {
font-family: 'Crimson Pro', Georgia, serif;
font-size: clamp(2rem, 5vw, 3.6rem);
font-weight: 700;
line-height: 1.15;
margin: 0 0 1.2rem;
color: #fff;
}
.kdoc-hero__sub {
font-size: clamp(1rem, 2.2vw, 1.2rem);
opacity: 0.88;
line-height: 1.65;
margin-bottom: 2rem;
}
.kdoc-hero__stats {
display: flex;
justify-content: center;
flex-wrap: wrap;
gap: 2rem 3rem;
margin: 2rem 0;
}
.kdoc-hero__stat {
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
}
.kdoc-hero__stat strong {
font-size: 2rem;
font-weight: 700;
font-family: 'Crimson Pro', serif;
color: #c9e0ff;
}
.kdoc-hero__stat span {
font-size: 0.78rem;
opacity: 0.75;
text-align: center;
}
.kdoc-hero__ctas {
display: flex;
justify-content: center;
flex-wrap: wrap;
gap: 12px;
margin-top: 2rem;
}
.kdoc-btn-primary {
display: inline-block;
background: var(--dbn-red, #ba0c2f);
color: #fff;
padding: 0.75rem 1.8rem;
border-radius: 4px;
font-weight: 600;
font-size: 0.95rem;
text-decoration: none;
transition: background 0.15s;
}
.kdoc-btn-primary:hover { background: #8f0921; }
.kdoc-btn-secondary {
display: inline-block;
background: rgba(255,255,255,0.12);
color: #fff;
border: 1px solid rgba(255,255,255,0.4);
padding: 0.75rem 1.6rem;
border-radius: 4px;
font-weight: 500;
font-size: 0.9rem;
text-decoration: none;
transition: background 0.15s;
}
.kdoc-btn-secondary:hover { background: rgba(255,255,255,0.22); }
/* ── Sections ────────────────────────────────────────────────────────── */
.kdoc-section {
max-width: 1100px;
margin: 0 auto;
padding: clamp(2.5rem, 5vw, 4.5rem) 2rem;
}
.kdoc-section--alt {
background: #edeae1;
}
.kdoc-section--alt .kdoc-section {
/* inner padding still applies */
}
.kdoc-section__eyebrow {
font-size: 0.75rem;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--dbn-red, #ba0c2f);
font-weight: 600;
margin-bottom: 0.6rem;
}
.kdoc-section__title {
font-family: 'Crimson Pro', Georgia, serif;
font-size: clamp(1.6rem, 3.5vw, 2.4rem);
font-weight: 700;
margin: 0 0 0.8rem;
color: var(--dbn-ink);
}
.kdoc-section__sub {
font-size: 1rem;
line-height: 1.7;
color: var(--dbn-ink);
opacity: 0.8;
max-width: 680px;
margin-bottom: 2rem;
}
/* ── Feature cards grid ─────────────────────────────────────────────── */
.kdoc-features {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 1.5rem;
margin-top: 1.5rem;
}
.kdoc-feature-card {
background: #fff;
border: 1px solid rgba(0,32,91,0.1);
border-radius: 8px;
padding: 1.6rem;
}
.kdoc-feature-card__icon {
font-size: 1.8rem;
margin-bottom: 0.8rem;
display: block;
}
.kdoc-feature-card__title {
font-family: 'Crimson Pro', serif;
font-size: 1.2rem;
font-weight: 700;
margin: 0 0 0.5rem;
color: var(--dbn-blue, #00205b);
}
.kdoc-feature-card__body {
font-size: 0.9rem;
line-height: 1.65;
color: var(--dbn-ink);
opacity: 0.85;
}
/* ── Simple 3-step pipeline (marketing page) ─────────────────────────── */
.kdoc-steps {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 0;
margin-top: 1.5rem;
position: relative;
}
.kdoc-step-card {
background: #fff;
border: 1px solid rgba(0,32,91,0.1);
border-radius: 8px;
padding: 1.8rem 1.6rem;
position: relative;
}
.kdoc-step-card__num {
display: inline-flex;
align-items: center;
justify-content: center;
width: 2.2rem;
height: 2.2rem;
border-radius: 50%;
background: var(--dbn-blue, #00205b);
color: #fff;
font-weight: 700;
font-size: 0.95rem;
margin-bottom: 1rem;
}
.kdoc-step-card__title {
font-family: 'Crimson Pro', serif;
font-size: 1.15rem;
font-weight: 700;
margin: 0 0 0.5rem;
color: var(--dbn-ink);
}
.kdoc-step-card__body {
font-size: 0.88rem;
line-height: 1.65;
color: var(--dbn-ink);
opacity: 0.82;
}
.kdoc-step-card__example {
margin-top: 0.8rem;
font-size: 0.8rem;
font-style: italic;
color: var(--dbn-blue);
opacity: 0.75;
}
@media (min-width: 700px) {
.kdoc-steps {
grid-template-columns: 1fr auto 1fr auto 1fr;
align-items: stretch;
}
.kdoc-step-arrow {
display: flex;
align-items: center;
padding: 0 0.5rem;
font-size: 1.4rem;
color: var(--dbn-blue);
opacity: 0.4;
}
}
.kdoc-step-arrow {
display: none;
}
/* ── Screenshot gallery ──────────────────────────────────────────────── */
.kdoc-gallery {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(380px, 1fr));
gap: 2rem;
margin-top: 1.5rem;
}
.kdoc-gallery__item {
display: flex;
flex-direction: column;
gap: 0.8rem;
}
.kdoc-screenshot {
border-radius: 8px;
box-shadow: 0 4px 24px rgba(0,0,0,0.12), 0 1px 4px rgba(0,0,0,0.08);
max-width: 100%;
border: 1px solid rgba(0,32,91,0.08);
}
.kdoc-gallery__caption {
font-size: 0.82rem;
color: var(--dbn-ink);
opacity: 0.65;
text-align: center;
}
/* ── LLM spotlight ───────────────────────────────────────────────────── */
.kdoc-llm-spotlight {
background: var(--dbn-blue, #00205b);
color: #fff;
border-radius: 10px;
padding: 2.5rem 2rem;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2rem;
align-items: center;
margin-top: 1.5rem;
}
@media (max-width: 640px) {
.kdoc-llm-spotlight { grid-template-columns: 1fr; }
}
.kdoc-llm-spotlight__badge {
display: inline-block;
background: rgba(255,255,255,0.15);
border: 1px solid rgba(255,255,255,0.3);
padding: 4px 12px;
border-radius: 20px;
font-size: 0.75rem;
font-weight: 600;
letter-spacing: 0.05em;
text-transform: uppercase;
margin-bottom: 0.8rem;
}
.kdoc-llm-spotlight__title {
font-family: 'Crimson Pro', serif;
font-size: 1.6rem;
font-weight: 700;
margin: 0 0 0.6rem;
}
.kdoc-llm-spotlight__body {
font-size: 0.9rem;
line-height: 1.7;
opacity: 0.88;
}
.kdoc-llm-stats {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
}
.kdoc-llm-stat {
background: rgba(255,255,255,0.1);
border-radius: 6px;
padding: 1rem;
}
.kdoc-llm-stat strong {
display: block;
font-size: 1.3rem;
font-family: 'Crimson Pro', serif;
color: #c9e0ff;
}
.kdoc-llm-stat span {
font-size: 0.78rem;
opacity: 0.75;
}
/* ── Authority body grid ─────────────────────────────────────────────── */
.kdoc-bodies {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 1rem;
margin-top: 1.5rem;
}
.kdoc-body-card {
background: #fff;
border: 1px solid rgba(0,32,91,0.1);
border-radius: 6px;
padding: 1rem 1.2rem;
}
.kdoc-body-card__name {
font-weight: 600;
font-size: 0.9rem;
color: var(--dbn-blue, #00205b);
margin-bottom: 4px;
}
.kdoc-body-card__law {
font-size: 0.75rem;
color: var(--dbn-ink);
opacity: 0.6;
font-style: italic;
}
/* ── CTA strip ───────────────────────────────────────────────────────── */
.kdoc-cta-strip {
background: var(--dbn-red, #ba0c2f);
color: #fff;
text-align: center;
padding: 4rem 2rem;
}
.kdoc-cta-strip__title {
font-family: 'Crimson Pro', serif;
font-size: clamp(1.6rem, 3.5vw, 2.4rem);
font-weight: 700;
margin: 0 0 0.8rem;
}
.kdoc-cta-strip__sub {
font-size: 1rem;
opacity: 0.88;
margin-bottom: 2rem;
}
.kdoc-cta-strip .kdoc-btn-primary {
background: #fff;
color: var(--dbn-red, #ba0c2f);
}
.kdoc-cta-strip .kdoc-btn-primary:hover {
background: #f5e8ea;
}
.kdoc-cta-strip .kdoc-btn-secondary {
border-color: rgba(255,255,255,0.5);
}
/* ── Guide: TOC ──────────────────────────────────────────────────────── */
.kdoc-toc {
background: #fff;
border: 1px solid rgba(0,32,91,0.1);
border-radius: 8px;
padding: 1.4rem 1.6rem;
margin: 0 0 2.5rem;
display: inline-block;
}
.kdoc-toc__title {
font-size: 0.78rem;
letter-spacing: 0.08em;
text-transform: uppercase;
font-weight: 600;
color: var(--dbn-ink);
opacity: 0.55;
margin-bottom: 0.8rem;
}
.kdoc-toc ol {
margin: 0;
padding-left: 1.2rem;
}
.kdoc-toc li {
font-size: 0.9rem;
margin-bottom: 0.3rem;
}
.kdoc-toc a {
color: var(--dbn-blue, #00205b);
text-decoration: none;
}
.kdoc-toc a:hover { text-decoration: underline; }
/* ── Guide: step sections ────────────────────────────────────────────── */
.kdoc-guide-step {
margin-bottom: 3.5rem;
scroll-margin-top: 2rem;
}
.kdoc-guide-step__header {
display: flex;
align-items: center;
gap: 1rem;
margin-bottom: 1rem;
}
.kdoc-guide-step__num {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 2rem;
height: 2rem;
border-radius: 50%;
background: var(--dbn-blue, #00205b);
color: #fff;
font-weight: 700;
font-size: 0.9rem;
flex-shrink: 0;
}
.kdoc-guide-step__title {
font-family: 'Crimson Pro', serif;
font-size: 1.35rem;
font-weight: 700;
margin: 0;
color: var(--dbn-ink);
}
.kdoc-guide-step__body {
font-size: 0.92rem;
line-height: 1.7;
color: var(--dbn-ink);
opacity: 0.88;
margin-bottom: 1.2rem;
}
.kdoc-guide-step__screenshot {
margin: 1rem 0;
}
/* ── Preset / tone table ─────────────────────────────────────────────── */
.kdoc-table {
width: 100%;
border-collapse: collapse;
font-size: 0.88rem;
margin: 1rem 0 1.5rem;
}
.kdoc-table th {
text-align: left;
font-weight: 600;
padding: 0.5rem 0.8rem;
border-bottom: 2px solid rgba(0,32,91,0.2);
color: var(--dbn-blue, #00205b);
font-size: 0.8rem;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.kdoc-table td {
padding: 0.6rem 0.8rem;
border-bottom: 1px solid rgba(0,32,91,0.08);
vertical-align: top;
line-height: 1.55;
}
.kdoc-table tr:last-child td { border-bottom: none; }
.kdoc-table td:first-child { font-weight: 600; color: var(--dbn-blue); white-space: nowrap; }
/* ── Guide: tips ─────────────────────────────────────────────────────── */
.kdoc-tips {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
gap: 1rem;
margin-top: 1rem;
}
.kdoc-tip {
background: #fff;
border-left: 3px solid var(--dbn-blue, #00205b);
border-radius: 0 6px 6px 0;
padding: 0.9rem 1.1rem;
font-size: 0.88rem;
line-height: 1.6;
color: var(--dbn-ink);
}
.kdoc-tip strong { color: var(--dbn-blue); }
/* ── Tech: pipeline diagram ──────────────────────────────────────────── */
.kdoc-pipeline {
display: flex;
flex-direction: column;
gap: 0;
margin: 1.5rem 0;
}
.kdoc-pipeline__pass {
background: #fff;
border: 1px solid rgba(0,32,91,0.12);
border-radius: 8px;
padding: 1.4rem 1.6rem;
position: relative;
}
.kdoc-pipeline__pass-badge {
display: inline-block;
background: var(--dbn-blue, #00205b);
color: #fff;
font-size: 0.7rem;
font-weight: 700;
letter-spacing: 0.06em;
text-transform: uppercase;
padding: 2px 8px;
border-radius: 3px;
margin-bottom: 0.6rem;
}
.kdoc-pipeline__pass-badge--mini { background: #0f766e; }
.kdoc-pipeline__pass-badge--optional { background: #6b7280; }
.kdoc-pipeline__pass-title {
font-family: 'Crimson Pro', serif;
font-size: 1.1rem;
font-weight: 700;
margin: 0 0 0.4rem;
color: var(--dbn-ink);
}
.kdoc-pipeline__pass-body {
font-size: 0.86rem;
line-height: 1.65;
color: var(--dbn-ink);
opacity: 0.82;
}
.kdoc-pipeline__pass ul {
margin: 0.5rem 0 0;
padding-left: 1.2rem;
font-size: 0.84rem;
line-height: 1.6;
}
.kdoc-pipeline__arrow-down {
text-align: center;
font-size: 1.2rem;
color: var(--dbn-blue);
opacity: 0.4;
padding: 4px 0;
}
@media (min-width: 760px) {
.kdoc-pipeline {
flex-direction: row;
align-items: stretch;
}
.kdoc-pipeline__pass {
flex: 1;
}
.kdoc-pipeline__arrow-down {
display: flex;
align-items: center;
padding: 0 4px;
font-size: 1.4rem;
}
}
/* ── Tech: KB stats ──────────────────────────────────────────────────── */
.kdoc-kb-stats {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
gap: 1rem;
margin: 1.5rem 0;
}
.kdoc-kb-stat {
background: #fff;
border: 1px solid rgba(0,32,91,0.1);
border-radius: 8px;
padding: 1.1rem 1.2rem;
text-align: center;
}
.kdoc-kb-stat strong {
display: block;
font-family: 'Crimson Pro', serif;
font-size: 1.9rem;
font-weight: 700;
color: var(--dbn-blue, #00205b);
line-height: 1;
margin-bottom: 4px;
}
.kdoc-kb-stat span {
font-size: 0.78rem;
color: var(--dbn-ink);
opacity: 0.65;
}
/* ── Tech: RAG diagram ───────────────────────────────────────────────── */
.kdoc-rag-flow {
display: flex;
flex-direction: column;
gap: 8px;
margin: 1.5rem 0;
}
.kdoc-rag-row {
display: flex;
align-items: center;
gap: 10px;
flex-wrap: wrap;
}
.kdoc-rag-box {
background: #fff;
border: 1px solid rgba(0,32,91,0.14);
border-radius: 5px;
padding: 0.6rem 1rem;
font-size: 0.82rem;
font-weight: 500;
color: var(--dbn-ink);
}
.kdoc-rag-box--blue {
background: var(--dbn-blue, #00205b);
color: #fff;
border-color: var(--dbn-blue);
}
.kdoc-rag-box--teal {
background: #0f766e;
color: #fff;
border-color: #0f766e;
}
.kdoc-rag-box--red {
background: var(--dbn-red, #ba0c2f);
color: #fff;
border-color: var(--dbn-red);
}
.kdoc-rag-arrow {
font-size: 1rem;
color: var(--dbn-blue);
opacity: 0.45;
}
.kdoc-slice-grid {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin: 0.8rem 0;
}
.kdoc-slice-chip {
background: rgba(0,32,91,0.08);
border: 1px solid rgba(0,32,91,0.14);
border-radius: 20px;
padding: 3px 10px;
font-size: 0.78rem;
font-weight: 500;
color: var(--dbn-blue, #00205b);
}
/* ── Tech: finetune block ────────────────────────────────────────────── */
.kdoc-finetune {
background: #1a2e4a;
color: #e8f0fb;
border-radius: 10px;
padding: 2rem 2rem;
margin-top: 1.5rem;
}
.kdoc-finetune__badge {
display: inline-block;
background: rgba(201,224,255,0.15);
border: 1px solid rgba(201,224,255,0.3);
padding: 3px 10px;
border-radius: 20px;
font-size: 0.73rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.07em;
margin-bottom: 0.8rem;
}
.kdoc-finetune__title {
font-family: 'Crimson Pro', serif;
font-size: 1.5rem;
font-weight: 700;
margin: 0 0 0.6rem;
color: #c9e0ff;
}
.kdoc-finetune__body {
font-size: 0.9rem;
line-height: 1.7;
opacity: 0.88;
}
.kdoc-finetune__chips {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-top: 1.2rem;
}
.kdoc-finetune__chip {
background: rgba(255,255,255,0.1);
border: 1px solid rgba(255,255,255,0.2);
border-radius: 4px;
padding: 4px 10px;
font-size: 0.78rem;
color: #c9e0ff;
font-family: 'IBM Plex Mono', monospace;
}
/* ── Tech: privacy block ─────────────────────────────────────────────── */
.kdoc-privacy {
background: #edeae1;
border-radius: 8px;
padding: 1.6rem 2rem;
margin-top: 1.5rem;
}
.kdoc-privacy__title {
font-weight: 700;
color: var(--dbn-blue, #00205b);
margin-bottom: 0.6rem;
}
.kdoc-privacy ul {
margin: 0;
padding-left: 1.3rem;
font-size: 0.88rem;
line-height: 1.8;
color: var(--dbn-ink);
}
/* ── Doc page nav-bar links row ──────────────────────────────────────── */
.kdoc-doc-nav {
background: rgba(0,32,91,0.04);
border-bottom: 1px solid rgba(0,32,91,0.08);
padding: 8px 2rem;
}
.kdoc-doc-nav__inner {
max-width: 1100px;
margin: 0 auto;
display: flex;
gap: 1.5rem;
font-size: 0.82rem;
flex-wrap: wrap;
}
.kdoc-doc-nav a {
color: var(--dbn-blue, #00205b);
text-decoration: none;
font-weight: 500;
padding: 4px 0;
border-bottom: 2px solid transparent;
}
.kdoc-doc-nav a:hover,
.kdoc-doc-nav a.is-active {
border-bottom-color: var(--dbn-blue);
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

+284
View File
@@ -0,0 +1,284 @@
<?php
declare(strict_types=1);
require_once __DIR__ . '/includes/bootstrap.php';
$uiLang = dbnToolsCurrentLanguage();
$isAuthed = dbnToolsIsAuthenticated();
$langPath = '/korrespond-about.php';
$toolsLogin = 'https://dobetternorge.no/tools-login.php?return=' . urlencode('/korrespond.php');
$registerUrl = 'https://dobetternorge.no/register.php';
$ctaUrl = $isAuthed ? '/korrespond.php' : ($toolsLogin);
?>
<!doctype html>
<html lang="<?= htmlspecialchars($uiLang) ?>">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Korrespond Draft letters to Norwegian authorities · Do Better Norge Tools</title>
<meta name="description" content="Korrespond uses Hard-RAG and a fine-tuned legal LLM to draft formal letters, emails, and court filings to Norwegian authorities — always in Norwegian bokmål + your language, with verified statute citations.">
<meta name="robots" content="index, follow">
<link rel="canonical" href="https://tools.dobetternorge.no/korrespond-about.php">
<meta property="og:title" content="Korrespond — Draft letters to Norwegian authorities">
<meta property="og:description" content="AI correspondence tool grounded in 220,000+ Norwegian legal passages. Covers NAV, Barnevernet, schools, Bufdir, Statsforvalter and more.">
<meta property="og:type" content="website">
<meta name="theme-color" content="#00205B">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Crimson+Pro:wght@400;600;700&family=IBM+Plex+Sans:wght@400;500;600;700&display=swap">
<link rel="stylesheet" href="assets/css/tools.css">
</head>
<body class="kdoc-page">
<header class="lt-nav">
<a href="https://dobetternorge.no" class="lt-nav__brand">
<picture>
<source srcset="assets/images/logo-header.webp" type="image/webp">
<img class="lt-nav__logo" src="assets/images/logo-header.png" alt="Do Better Norge" width="140" height="36" loading="eager">
</picture>
<span class="lt-nav__badge">Legal Tools</span>
</a>
<div class="lt-nav__right">
<nav class="shell-lang-switcher" aria-label="Language">
<?php foreach (dbnToolsSupportedLanguages() as $langCode): ?>
<a href="<?= htmlspecialchars($langPath . '?lang=' . $langCode) ?>" class="<?= $langCode === $uiLang ? 'is-active' : '' ?>"><?= htmlspecialchars(dbnToolsLanguageLabel($langCode)) ?></a>
<?php endforeach; ?>
</nav>
<?php if ($isAuthed): ?>
<a href="/korrespond.php" class="lt-nav__cta lt-nav__cta--enter">Open Korrespond &rarr;</a>
<?php else: ?>
<a href="<?= htmlspecialchars($toolsLogin) ?>" class="lt-nav__cta">Sign in</a>
<?php endif; ?>
</div>
</header>
<!-- Doc nav: links to all 3 doc pages -->
<nav class="kdoc-doc-nav" aria-label="Korrespond documentation">
<div class="kdoc-doc-nav__inner">
<a href="/korrespond-about.php" class="is-active">About</a>
<a href="/korrespond-guide.php">User guide</a>
<a href="/korrespond-tech.php">How it works</a>
<?php if ($isAuthed): ?>
<a href="/korrespond.php">&larr; Open the tool</a>
<?php endif; ?>
</div>
</nav>
<!-- Hero -->
<section class="kdoc-hero" style="background: linear-gradient(rgba(0,20,60,0.82),rgba(0,20,60,0.88)), url('assets/images/korrespond/hero-marketing.png') center/cover no-repeat;">
<div class="kdoc-hero__inner">
<p class="kdoc-hero__kicker">AI Correspondence &middot; Norwegian Authorities &middot; Hard-RAG Grounded</p>
<h1 class="kdoc-hero__title">Draft the letter that changes everything.</h1>
<p class="kdoc-hero__sub">Korrespond turns your situation into a polished, statute-grounded letter, email, or court filing always in Norwegian bokmål plus your working language, side by side. Every § citation is verified against 220,000+ indexed legal passages before it reaches you.</p>
<div class="kdoc-hero__stats">
<div class="kdoc-hero__stat">
<strong>220K+</strong>
<span>legal passages indexed</span>
</div>
<div class="kdoc-hero__stat">
<strong>11</strong>
<span>authority presets</span>
</div>
<div class="kdoc-hero__stat">
<strong>4</strong>
<span>output types</span>
</div>
<div class="kdoc-hero__stat">
<strong>3</strong>
<span>pipeline passes</span>
</div>
</div>
<div class="kdoc-hero__ctas">
<a href="<?= htmlspecialchars($ctaUrl) ?>" class="kdoc-btn-primary">Try Korrespond free &rarr;</a>
<a href="/korrespond-guide.php" class="kdoc-btn-secondary">User guide</a>
<a href="/korrespond-tech.php" class="kdoc-btn-secondary">How it works</a>
</div>
</div>
</section>
<!-- What you get -->
<section class="kdoc-section--alt">
<div class="kdoc-section">
<p class="kdoc-section__eyebrow">What you get</p>
<h2 class="kdoc-section__title">Three things no other tool gives you at once.</h2>
<div class="kdoc-features">
<div class="kdoc-feature-card">
<span class="kdoc-feature-card__icon">&#127475;&#127476;</span>
<h3 class="kdoc-feature-card__title">Always Norwegian + your language</h3>
<p class="kdoc-feature-card__body">The canonical draft is always Norwegian bokmål the legally operative form. Your working language (English, Polish, or Ukrainian) appears side-by-side as a reference column. Copy either version with one click.</p>
</div>
<div class="kdoc-feature-card">
<span class="kdoc-feature-card__icon">&#128220;</span>
<h3 class="kdoc-feature-card__title">Hard-RAG: no hallucinated statutes</h3>
<p class="kdoc-feature-card__body">Every § number in the draft is traced to a specific retrieved passage from the legal corpus before it reaches you. The self-check pass strips any citation that can't be verified. If no statute fits the draft says so plainly, without fake references.</p>
</div>
<div class="kdoc-feature-card">
<span class="kdoc-feature-card__icon">&#9878;&#65039;</span>
<h3 class="kdoc-feature-card__title">Covers the statutes that matter</h3>
<p class="kdoc-feature-card__body">forvaltningsloven (fvl §§ 17, 18, 24-25, 28, 32), barnevernsloven, NAV-loven, opplæringslova, barnehageloven, and EMK Art. 6 &amp; 8 all reachable by selecting the right recipient body. Optional second pass pulls formal ECHR case citations (Strand Lobben, Johansen, K.O. and V.M.).</p>
</div>
</div>
</div>
</section>
<!-- How it works (3-step) -->
<div class="kdoc-section">
<p class="kdoc-section__eyebrow">How it works</p>
<h2 class="kdoc-section__title">Describe retrieve draft. In under a minute.</h2>
<p class="kdoc-section__sub">Three steps from blank form to ready-to-send letter. No legal training required.</p>
<div class="kdoc-steps">
<div class="kdoc-step-card">
<span class="kdoc-step-card__num">1</span>
<h3 class="kdoc-step-card__title">Describe your situation</h3>
<p class="kdoc-step-card__body">Choose the authority you're writing to, select your output type and tone, and describe what happened. Pick a goal chip (appeal, access to documents, request meeting…) or write your own. Upload the original letter if replying.</p>
<p class="kdoc-step-card__example">E.g. &ldquo;NAV denied my application. I want to appeal and demand a reasoned decision.&rdquo;</p>
</div>
<span class="kdoc-step-arrow" aria-hidden="true">&rarr;</span>
<div class="kdoc-step-card">
<span class="kdoc-step-card__num">2</span>
<h3 class="kdoc-step-card__title">AI retrieves applicable law &amp; drafts</h3>
<p class="kdoc-step-card__body">The pipeline classifies your situation, identifies the relevant statute set for your chosen authority, retrieves the top matching passages from 220,000+ indexed sources, and drafts a formal letter citing only what it actually found.</p>
<p class="kdoc-step-card__example">Produces two-column output: Norsk (bokmål) canonical + your working language reference.</p>
</div>
<span class="kdoc-step-arrow" aria-hidden="true">&rarr;</span>
<div class="kdoc-step-card">
<span class="kdoc-step-card__num">3</span>
<h3 class="kdoc-step-card__title">Refine with formal citations</h3>
<p class="kdoc-step-card__body">Optional second pass: choose Norwegian law, ECHR, or both. The tool rewrites the draft with court-ready citation style <em>jf. forvaltningsloven § 17</em>, <em>Strand Lobben m.fl. mot Norge, EMD-37283/13, §§ 207214</em> and appends a Rettskilder (legal sources) block.</p>
<p class="kdoc-step-card__example">Costs one extra credit. Takes ~30 seconds.</p>
</div>
</div>
</div>
<!-- Screenshots -->
<section class="kdoc-section--alt">
<div class="kdoc-section">
<p class="kdoc-section__eyebrow">Screenshots</p>
<h2 class="kdoc-section__title">See it in action.</h2>
<div class="kdoc-gallery">
<div class="kdoc-gallery__item">
<img src="assets/images/korrespond/form-top.png" alt="Korrespond form — mode toggle, recipient body, output type, tone" class="kdoc-screenshot" loading="lazy">
<p class="kdoc-gallery__caption">The intake form: choose recipient body, output type, and tone in seconds.</p>
</div>
<div class="kdoc-gallery__item">
<img src="assets/images/korrespond/output-draft.png" alt="Korrespond output — two-column side-by-side Norwegian and English draft" class="kdoc-screenshot" loading="lazy">
<p class="kdoc-gallery__caption">Two-column output: Norwegian bokmål canonical on the left, English reference on the right.</p>
</div>
<div class="kdoc-gallery__item">
<img src="assets/images/korrespond/refine-panel.png" alt="Refine panel with jurisdiction options" class="kdoc-screenshot" loading="lazy">
<p class="kdoc-gallery__caption">The optional Refine pass choose Norwegian law, ECHR, or both.</p>
</div>
<div class="kdoc-gallery__item">
<img src="assets/images/korrespond/output-refined.png" alt="Refined output with formal statute and ECHR citations" class="kdoc-screenshot" loading="lazy">
<p class="kdoc-gallery__caption">After refinement: formal citations like <em>jf. opplæringslova § 9 A-4</em> and <em>EMK artikkel 8</em>.</p>
</div>
</div>
</div>
</section>
<!-- Fine-tuned LLM spotlight -->
<div class="kdoc-section">
<p class="kdoc-section__eyebrow">Under the hood</p>
<h2 class="kdoc-section__title">Powered by a purpose-built legal LLM.</h2>
<div class="kdoc-llm-spotlight">
<div>
<span class="kdoc-llm-spotlight__badge">Fine-tuned model</span>
<h3 class="kdoc-llm-spotlight__title">dbn-legal-agent</h3>
<p class="kdoc-llm-spotlight__body">A QLoRA fine-tune trained on Norwegian child-welfare and administrative law text. Unlike a general-purpose LLM, dbn-legal-agent understands the procedural vocabulary of forvaltningsloven what a <em>klage</em> requires, what triggers fvl § 17 consultation rights, how Barnevernet decisions must be reasoned under § 6-3. It runs alongside Azure gpt-4o to shape the structure and register of every draft.</p>
</div>
<div class="kdoc-llm-stats">
<div class="kdoc-llm-stat">
<strong>QLoRA</strong>
<span>fine-tune method</span>
</div>
<div class="kdoc-llm-stat">
<strong>fvl</strong>
<span>procedural vocabulary</span>
</div>
<div class="kdoc-llm-stat">
<strong>gpt-4o</strong>
<span>drafting backbone</span>
</div>
<div class="kdoc-llm-stat">
<strong>3-pass</strong>
<span>pipeline architecture</span>
</div>
</div>
</div>
</div>
<!-- Authority coverage -->
<section class="kdoc-section--alt">
<div class="kdoc-section">
<p class="kdoc-section__eyebrow">Authority coverage</p>
<h2 class="kdoc-section__title">11 presets. Each loads the right statutes automatically.</h2>
<p class="kdoc-section__sub">Selecting a recipient body pre-loads the relevant statute set into the Hard-RAG retrieval. No need to know which laws apply the tool does that for you.</p>
<div class="kdoc-bodies">
<div class="kdoc-body-card">
<p class="kdoc-body-card__name">Barnehage</p>
<p class="kdoc-body-card__law">barnehageloven · fvl</p>
</div>
<div class="kdoc-body-card">
<p class="kdoc-body-card__name">Skole (1.10. trinn)</p>
<p class="kdoc-body-card__law">opplæringslova · fvl</p>
</div>
<div class="kdoc-body-card">
<p class="kdoc-body-card__name">SFO</p>
<p class="kdoc-body-card__law">opplæringslova · fvl</p>
</div>
<div class="kdoc-body-card">
<p class="kdoc-body-card__name">NAV</p>
<p class="kdoc-body-card__law">NAV-loven · fvl</p>
</div>
<div class="kdoc-body-card">
<p class="kdoc-body-card__name">Bufdir</p>
<p class="kdoc-body-card__law">fvl · EMK Art. 8</p>
</div>
<div class="kdoc-body-card">
<p class="kdoc-body-card__name">Barnevernet</p>
<p class="kdoc-body-card__law">barnevernsloven · fvl · EMK</p>
</div>
<div class="kdoc-body-card">
<p class="kdoc-body-card__name">Kommune (annet)</p>
<p class="kdoc-body-card__law">fvl</p>
</div>
<div class="kdoc-body-card">
<p class="kdoc-body-card__name">Statsforvalteren</p>
<p class="kdoc-body-card__law">fvl · barnevernsloven</p>
</div>
<div class="kdoc-body-card">
<p class="kdoc-body-card__name">Trygderetten</p>
<p class="kdoc-body-card__law">trygderettsloven · fvl</p>
</div>
<div class="kdoc-body-card">
<p class="kdoc-body-card__name">Tingretten</p>
<p class="kdoc-body-card__law">tvisteloven · EMK Art. 6</p>
</div>
<div class="kdoc-body-card">
<p class="kdoc-body-card__name">Annet</p>
<p class="kdoc-body-card__law">fvl (general)</p>
</div>
</div>
</div>
</section>
<!-- CTA strip -->
<section class="kdoc-cta-strip">
<h2 class="kdoc-cta-strip__title">Ready to draft your letter?</h2>
<p class="kdoc-cta-strip__sub">Free for Do Better Norge members. No credit card required.</p>
<div class="kdoc-hero__ctas">
<?php if ($isAuthed): ?>
<a href="/korrespond.php" class="kdoc-btn-primary">Open Korrespond &rarr;</a>
<?php else: ?>
<a href="<?= htmlspecialchars($toolsLogin) ?>" class="kdoc-btn-primary">Sign in to use Korrespond &rarr;</a>
<a href="<?= htmlspecialchars($registerUrl) ?>" class="kdoc-btn-secondary">Register free</a>
<?php endif; ?>
</div>
</section>
<?php require_once __DIR__ . '/includes/footer.php'; ?>
<script src="assets/js/tools.js" defer></script>
</body>
</html>
+403
View File
@@ -0,0 +1,403 @@
<?php
declare(strict_types=1);
require_once __DIR__ . '/includes/bootstrap.php';
$uiLang = dbnToolsCurrentLanguage();
$isAuthed = dbnToolsIsAuthenticated();
$langPath = '/korrespond-guide.php';
$toolsLogin = 'https://dobetternorge.no/tools-login.php?return=' . urlencode('/korrespond.php');
$registerUrl = 'https://dobetternorge.no/register.php';
?>
<!doctype html>
<html lang="<?= htmlspecialchars($uiLang) ?>">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Korrespond User Guide How to draft letters to Norwegian authorities</title>
<meta name="description" content="Step-by-step guide to using Korrespond: choose a mode, select the right authority, set tone, describe your situation, and understand the output.">
<meta name="robots" content="index, follow">
<link rel="canonical" href="https://tools.dobetternorge.no/korrespond-guide.php">
<meta property="og:title" content="Korrespond User Guide">
<meta property="og:description" content="How to use Korrespond to draft letters, emails and court filings to Norwegian authorities.">
<meta name="theme-color" content="#00205B">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Crimson+Pro:wght@400;600;700&family=IBM+Plex+Sans:wght@400;500;600;700&display=swap">
<link rel="stylesheet" href="assets/css/tools.css">
</head>
<body class="kdoc-page">
<header class="lt-nav">
<a href="https://dobetternorge.no" class="lt-nav__brand">
<picture>
<source srcset="assets/images/logo-header.webp" type="image/webp">
<img class="lt-nav__logo" src="assets/images/logo-header.png" alt="Do Better Norge" width="140" height="36" loading="eager">
</picture>
<span class="lt-nav__badge">Legal Tools</span>
</a>
<div class="lt-nav__right">
<nav class="shell-lang-switcher" aria-label="Language">
<?php foreach (dbnToolsSupportedLanguages() as $langCode): ?>
<a href="<?= htmlspecialchars($langPath . '?lang=' . $langCode) ?>" class="<?= $langCode === $uiLang ? 'is-active' : '' ?>"><?= htmlspecialchars(dbnToolsLanguageLabel($langCode)) ?></a>
<?php endforeach; ?>
</nav>
<?php if ($isAuthed): ?>
<a href="/korrespond.php" class="lt-nav__cta lt-nav__cta--enter">Open Korrespond &rarr;</a>
<?php else: ?>
<a href="<?= htmlspecialchars($toolsLogin) ?>" class="lt-nav__cta">Sign in</a>
<?php endif; ?>
</div>
</header>
<nav class="kdoc-doc-nav" aria-label="Korrespond documentation">
<div class="kdoc-doc-nav__inner">
<a href="/korrespond-about.php">About</a>
<a href="/korrespond-guide.php" class="is-active">User guide</a>
<a href="/korrespond-tech.php">How it works</a>
<?php if ($isAuthed): ?><a href="/korrespond.php">&larr; Open the tool</a><?php endif; ?>
</div>
</nav>
<!-- Hero -->
<section class="kdoc-hero" style="background: linear-gradient(rgba(0,20,60,0.78),rgba(0,20,60,0.86)), url('assets/images/korrespond/hero-guide.png') center/cover no-repeat;">
<div class="kdoc-hero__inner">
<p class="kdoc-hero__kicker">User Guide &middot; Korrespond</p>
<h1 class="kdoc-hero__title">How to use Korrespond.</h1>
<p class="kdoc-hero__sub">A step-by-step walkthrough of every control from choosing your mode to understanding the output and using the formal citation refine pass.</p>
</div>
</section>
<!-- TOC + content -->
<div class="kdoc-section">
<div class="kdoc-toc">
<p class="kdoc-toc__title">In this guide</p>
<ol>
<li><a href="#mode">Choose a mode: Reply or Initiate</a></li>
<li><a href="#body">Choose the recipient body</a></li>
<li><a href="#output">Output type</a></li>
<li><a href="#tone">Tone</a></li>
<li><a href="#context">Context fields</a></li>
<li><a href="#narrative">Describe the situation &amp; goal chips</a></li>
<li><a href="#upload">Upload files (Reply mode)</a></li>
<li><a href="#clarify">The clarify gate</a></li>
<li><a href="#output-result">Understanding the output</a></li>
<li><a href="#refine">Using the Refine pass</a></li>
<li><a href="#tips">Tips &amp; gotchas</a></li>
</ol>
</div>
<!-- Step 1: Mode -->
<div class="kdoc-guide-step" id="mode">
<div class="kdoc-guide-step__header">
<span class="kdoc-guide-step__num">1</span>
<h2 class="kdoc-guide-step__title">Choose a mode: Reply or Initiate</h2>
</div>
<div class="kdoc-guide-step__screenshot">
<img src="assets/images/korrespond/form-top.png" alt="Mode toggle showing Reply and Initiate options" class="kdoc-screenshot" style="max-width:700px;" loading="lazy">
</div>
<div class="kdoc-guide-step__body">
<p><strong>Reply mode</strong> is for when you have received a letter, decision, or notice and need to respond to it. Upload the document (PDF, DOCX, or TXT) and the tool will read it as the basis for your reply. You can still add narrative context.</p>
<p style="margin-top:0.8rem;"><strong>Initiate mode</strong> is for when you want to start a new correspondence from scratch no incoming document. You'll describe the situation in the "What happened" field. This mode is required for the narrative field.</p>
</div>
</div>
<!-- Step 2: Recipient body -->
<div class="kdoc-guide-step" id="body">
<div class="kdoc-guide-step__header">
<span class="kdoc-guide-step__num">2</span>
<h2 class="kdoc-guide-step__title">Choose the recipient body</h2>
</div>
<div class="kdoc-guide-step__body">
<p>The recipient body dropdown pre-loads the relevant statute set into the Hard-RAG retrieval pipeline. Choosing correctly means the tool searches the right laws you don't need to know which statutes apply yourself.</p>
</div>
<table class="kdoc-table">
<thead>
<tr>
<th>Recipient</th>
<th>Statutes loaded</th>
<th>Typical use</th>
</tr>
</thead>
<tbody>
<tr>
<td>Barnehage</td>
<td>barnehageloven · fvl</td>
<td>Enrolment disputes, special needs provisions</td>
</tr>
<tr>
<td>Skole (1.10. trinn)</td>
<td>opplæringslova · fvl</td>
<td>Access to education, psycho-social environment</td>
</tr>
<tr>
<td>SFO</td>
<td>opplæringslova · fvl</td>
<td>After-school care disputes</td>
</tr>
<tr>
<td>NAV</td>
<td>NAV-loven · fvl</td>
<td>Benefit denials, appeal of decisions</td>
</tr>
<tr>
<td>Bufdir</td>
<td>fvl · EMK Art. 8</td>
<td>Adoption, surrogacy, family reunification</td>
</tr>
<tr>
<td>Barnevernet</td>
<td>barnevernsloven · fvl · EMK Art. 8</td>
<td>Care orders, emergency placements, tiltaksplan</td>
</tr>
<tr>
<td>Statsforvalteren</td>
<td>fvl · barnevernsloven</td>
<td>Complaints about municipality / Barnevernet</td>
</tr>
<tr>
<td>Trygderetten</td>
<td>trygderettsloven · fvl</td>
<td>Social security tribunal appeals</td>
</tr>
<tr>
<td>Tingretten</td>
<td>tvisteloven · EMK Art. 6</td>
<td>Court filings, procedural motions</td>
</tr>
<tr>
<td>Kommune (annet)</td>
<td>fvl</td>
<td>Any other municipal body</td>
</tr>
<tr>
<td>Annet</td>
<td>fvl (general)</td>
<td>Authorities not in the list above</td>
</tr>
</tbody>
</table>
</div>
<!-- Step 3: Output type -->
<div class="kdoc-guide-step" id="output">
<div class="kdoc-guide-step__header">
<span class="kdoc-guide-step__num">3</span>
<h2 class="kdoc-guide-step__title">Output type</h2>
</div>
<div class="kdoc-guide-step__body">
<p>Choose the format that fits what you need to send.</p>
</div>
<table class="kdoc-table">
<thead>
<tr><th>Type</th><th>When to use it</th><th>Structure</th></tr>
</thead>
<tbody>
<tr>
<td>Email</td>
<td>Day-to-day correspondence, quick inquiries, follow-ups</td>
<td>Short subject + body with signature</td>
</tr>
<tr>
<td>Formal letter</td>
<td>Official complaints, appeals, access-to-documents requests</td>
<td>Sender/receiver block, date, reference, body, signature</td>
</tr>
<tr>
<td>Court/tribunal filing</td>
<td>Submissions to Tingretten or Trygderetten</td>
<td>Numbered sections, legal argument structure, prayer for relief</td>
</tr>
<tr>
<td>Phone-call prep</td>
<td>Before calling a caseworker or authority</td>
<td>Opening line · key facts · statutes to cite if pressed · questions to ask · escalation path</td>
</tr>
</tbody>
</table>
</div>
<!-- Step 4: Tone -->
<div class="kdoc-guide-step" id="tone">
<div class="kdoc-guide-step__header">
<span class="kdoc-guide-step__num">4</span>
<h2 class="kdoc-guide-step__title">Tone</h2>
</div>
<div class="kdoc-guide-step__body">
<p>Tone affects the register and directness of the draft not the legal accuracy. The AI will maintain correct Norwegian procedural formality regardless of tone.</p>
</div>
<table class="kdoc-table">
<thead>
<tr><th>Tone</th><th>When to use it</th></tr>
</thead>
<tbody>
<tr>
<td>Cooperative</td>
<td>First contact, relationship still intact, no conflict yet</td>
</tr>
<tr>
<td>Neutral-professional &#9733;</td>
<td>Default. Works for most situations factual, polite, direct</td>
</tr>
<tr>
<td>Firm</td>
<td>Deadline has passed, previous requests ignored, clear legal obligation exists</td>
</tr>
<tr>
<td>Adversarial</td>
<td>Formal complaints, escalations, when cooperation has broken down completely. Use intentionally sets a confrontational tone that can close doors.</td>
</tr>
<tr>
<td>Conciliatory-warm</td>
<td>De-escalation, apology situations, requesting a second chance or meeting</td>
</tr>
</tbody>
</table>
</div>
<!-- Step 5: Context fields -->
<div class="kdoc-guide-step" id="context">
<div class="kdoc-guide-step__header">
<span class="kdoc-guide-step__num">5</span>
<h2 class="kdoc-guide-step__title">Context fields</h2>
</div>
<div class="kdoc-guide-step__body">
<p><strong>Case reference (saksnummer):</strong> The reference number on any letter you've received. Providing this helps the AI draft precise references in the header. If you don't have one yet, leave it blank.</p>
<p style="margin-top:0.8rem;"><strong>Where (kommune / fylke):</strong> The geographical location of the authority. This helps the AI address the letter correctly and can affect which specific regulations apply (e.g. local school rules).</p>
<p style="margin-top:0.8rem;"><strong>Next deadline:</strong> If there's a deadline for your response or action, enter it here. The AI will include an explicit deadline reference in the letter where appropriate. Accepts YYYY-MM-DD or plain text like "3 weeks from today".</p>
<p style="margin-top:0.8rem;"><strong>Who is involved:</strong> Names and roles of the key parties you, any caseworker, the child if relevant, a lawyer, etc. Keep it brief (e.g. "Me (parent), caseworker Anna Hansen, son Ola (age 8)"). <em>Tip: use the Redact tool first if you'll share this externally.</em></p>
</div>
</div>
<!-- Step 6: Narrative + goal chips -->
<div class="kdoc-guide-step" id="narrative">
<div class="kdoc-guide-step__header">
<span class="kdoc-guide-step__num">6</span>
<h2 class="kdoc-guide-step__title">Describe the situation &amp; choose a goal</h2>
</div>
<div class="kdoc-guide-step__screenshot">
<img src="assets/images/korrespond/form-bottom.png" alt="Narrative field and goal chips" class="kdoc-screenshot" style="max-width:700px;" loading="lazy">
</div>
<div class="kdoc-guide-step__body">
<p><strong>"What happened / context"</strong> is the most important field. Write what happened, when, who decided what, and what outcome you want. The more specific you are, the better the draft. 8,000 characters maximum.</p>
<p style="margin-top:0.8rem;"><strong>Goal chips</strong> let you quickly state your legal goal. Click one to auto-fill the Goal field you can then edit it. Each chip maps to a specific procedural right:</p>
<ul style="margin-top:0.6rem; padding-left:1.4rem; font-size:0.9rem; line-height:1.8;">
<li><strong>Access to docs (fvl §18)</strong> Request access to all documents in your case</li>
<li><strong>Appeal (fvl §28)</strong> Formally appeal a decision to the klageinstans</li>
<li><strong>Request meeting</strong> Request a face-to-face meeting with a caseworker</li>
<li><strong>Reasoned decision (fvl §24-25)</strong> Demand a written, reasoned decision</li>
<li><strong>Right to be heard (fvl §17)</strong> Invoke your procedural right to be heard before a decision</li>
<li><strong>Complaint</strong> File a complaint about caseworker conduct</li>
<li><strong>Clarify timeline</strong> Ask for a status update and expected timeline</li>
</ul>
<p style="margin-top:0.8rem;">You can type your own goal in the text field instead of or in addition to using a chip.</p>
</div>
</div>
<!-- Step 7: Upload -->
<div class="kdoc-guide-step" id="upload">
<div class="kdoc-guide-step__header">
<span class="kdoc-guide-step__num">7</span>
<h2 class="kdoc-guide-step__title">Upload files (Reply mode)</h2>
</div>
<div class="kdoc-guide-step__body">
<p>In <strong>Reply mode</strong>, upload the letter or decision you received. The AI will read and summarise it as the basis for your reply. Supported formats: <strong>PDF</strong>, <strong>DOCX</strong>, <strong>TXT</strong>. Up to 4 files, max 8 MB each.</p>
<p style="margin-top:0.8rem;"><strong>Convention:</strong> the first file uploaded is treated as the primary received letter. Additional files are treated as supporting attachments (e.g. previous correspondence, evidence).</p>
<p style="margin-top:0.8rem;">In <strong>Initiate mode</strong>, uploads are optional use them to provide supporting context (previous letters, medical reports, etc.).</p>
<p style="margin-top:0.8rem;">All files are processed in memory and immediately discarded when the session ends. Nothing is written to disk or retained.</p>
</div>
</div>
<!-- Step 8: Clarify gate -->
<div class="kdoc-guide-step" id="clarify">
<div class="kdoc-guide-step__header">
<span class="kdoc-guide-step__num">8</span>
<h2 class="kdoc-guide-step__title">The clarify gate</h2>
</div>
<div class="kdoc-guide-step__body">
<p>Before drafting, the AI runs a quick classification pass (Pass 1) to understand your situation. If it finds gaps that would significantly affect the quality of the draft a missing decision date, unclear which child is involved, unknown authority it pauses and shows a <strong>"Before we draft, clarify:"</strong> panel with specific questions.</p>
<p style="margin-top:0.8rem;"><strong>Answer what you can</strong>, then click <em>Continue draft</em>. Your answers are merged into the context before Pass 2 runs. This extra step costs no additional credit.</p>
<p style="margin-top:0.8rem;">If you're in a hurry or simply don't know the answers, click <em>Draft anyway</em>. The tool will proceed with what it has and flag uncertainties in the output.</p>
<p style="margin-top:0.8rem;"><strong>Note:</strong> the clarify pass is free. Credits are only deducted when the actual drafting (Pass 2) begins.</p>
</div>
</div>
<!-- Step 9: Understanding the output -->
<div class="kdoc-guide-step" id="output-result">
<div class="kdoc-guide-step__header">
<span class="kdoc-guide-step__num">9</span>
<h2 class="kdoc-guide-step__title">Understanding the output</h2>
</div>
<div class="kdoc-guide-step__screenshot">
<img src="assets/images/korrespond/output-draft.png" alt="Two-column output: Norwegian bokmål and English side by side" class="kdoc-screenshot" style="max-width:800px;" loading="lazy">
</div>
<div class="kdoc-guide-step__body">
<p>The output has two columns:</p>
<ul style="padding-left:1.4rem; font-size:0.9rem; line-height:1.8; margin-top:0.5rem;">
<li><strong>Norsk (bokmål) canonical:</strong> The legally operative draft. This is what you send. Use the Copy or Download .txt button to get the text.</li>
<li><strong>Working language reference:</strong> A translation into your working language (EN/PL/UK). Use this to understand what you're sending do not send this version to the authority.</li>
</ul>
<p style="margin-top:0.8rem;"><strong>Cited law note:</strong> at the bottom of the output, a note shows how many law sources were retrieved and cited. If it says "No cited law sources — draft is plain-language", it means no statute matched your situation closely enough to cite the draft will still be useful but won't include § references. This is the honest behaviour: no fake citations.</p>
</div>
</div>
<!-- Step 10: Refine -->
<div class="kdoc-guide-step" id="refine">
<div class="kdoc-guide-step__header">
<span class="kdoc-guide-step__num">10</span>
<h2 class="kdoc-guide-step__title">Using the Refine pass</h2>
</div>
<div class="kdoc-guide-step__screenshot">
<img src="assets/images/korrespond/refine-panel.png" alt="Refine panel with Norwegian law, ECHR, and Both options" class="kdoc-screenshot" style="max-width:700px;" loading="lazy">
</div>
<div class="kdoc-guide-step__body">
<p>The <strong>Refine with formal citations</strong> panel appears after the initial draft. This optional second pass (+1 credit) rewrites the draft with court-ready citation style and appends a Rettskilder (legal sources) block at the end.</p>
<p style="margin-top:0.8rem;">Choose your jurisdiction scope:</p>
<ul style="padding-left:1.4rem; font-size:0.9rem; line-height:1.8; margin-top:0.5rem;">
<li><strong>Norwegian law only:</strong> Rewrites to use <em>jf. forvaltningsloven § 17</em>, <em>jf. opplæringslova § 9 A-4</em> style. Best for most domestic correspondence.</li>
<li><strong>ECHR (EMK + HUDOC):</strong> Adds European Court of Human Rights citations with full case name, application number, date, and paragraph e.g. <em>Strand Lobben m.fl. mot Norge, EMD-37283/13 (17.09.2019), § 207</em>. Use when arguing family life rights (Art. 8) or fair trial (Art. 6).</li>
<li><strong>Both:</strong> Combines Norwegian statute citations with ECHR case law. Strongest for Barnevernet, Bufdir, or court filings where both domestic and ECHR grounds apply.</li>
</ul>
</div>
<div class="kdoc-guide-step__screenshot" style="margin-top:1rem;">
<img src="assets/images/korrespond/output-refined.png" alt="Refined output with formal citations including opplæringslova and EMK" class="kdoc-screenshot" style="max-width:800px;" loading="lazy">
</div>
</div>
<!-- Step 11: Tips -->
<div class="kdoc-guide-step" id="tips">
<div class="kdoc-guide-step__header">
<span class="kdoc-guide-step__num">11</span>
<h2 class="kdoc-guide-step__title">Tips &amp; gotchas</h2>
</div>
<div class="kdoc-tips">
<div class="kdoc-tip"><strong>Use the Redact tool first.</strong> If your narrative includes full names, fødselsnumre, or addresses, run it through Redact before pasting into Korrespond especially if you plan to share the output.</div>
<div class="kdoc-tip"><strong>Saksnummer helps a lot.</strong> Even a partial case reference from a letter header helps the AI address the reply correctly and cite the right case context.</div>
<div class="kdoc-tip"><strong>Adversarial tone is powerful use it intentionally.</strong> It signals formal conflict escalation. Once sent, it can close cooperative doors. Use Firm first unless you've genuinely exhausted other options.</div>
<div class="kdoc-tip"><strong>Goal chips stack with the narrative.</strong> If you pick "Appeal (fvl §28)" but your narrative also mentions access to documents, the AI will address both you don't need to pick just one chip.</div>
<div class="kdoc-tip"><strong>Deadline field affects the draft directly.</strong> The AI explicitly states the deadline in the letter and frames the request with urgency where appropriate. Always fill it in if one exists.</div>
<div class="kdoc-tip"><strong>For ECHR citations, choose Barnevernet or Bufdir as body.</strong> Those presets load the ECHR + family law corpus slices. The Refine pass will then find the strongest relevant case law (Strand Lobben, Johansen, K.O. and V.M.).</div>
</div>
</div>
</div><!-- /kdoc-section -->
<!-- CTA -->
<section class="kdoc-cta-strip">
<h2 class="kdoc-cta-strip__title">Ready to try it?</h2>
<p class="kdoc-cta-strip__sub">Free for Do Better Norge members.</p>
<div class="kdoc-hero__ctas">
<?php if ($isAuthed): ?>
<a href="/korrespond.php" class="kdoc-btn-primary">Open Korrespond &rarr;</a>
<?php else: ?>
<a href="<?= htmlspecialchars($toolsLogin) ?>" class="kdoc-btn-primary">Sign in to use Korrespond &rarr;</a>
<a href="<?= htmlspecialchars($registerUrl) ?>" class="kdoc-btn-secondary">Register free</a>
<?php endif; ?>
<a href="/korrespond-tech.php" class="kdoc-btn-secondary">How it works under the hood</a>
</div>
</section>
<?php require_once __DIR__ . '/includes/footer.php'; ?>
<script src="assets/js/tools.js" defer></script>
</body>
</html>
+342
View File
@@ -0,0 +1,342 @@
<?php
declare(strict_types=1);
require_once __DIR__ . '/includes/bootstrap.php';
$uiLang = dbnToolsCurrentLanguage();
$isAuthed = dbnToolsIsAuthenticated();
$langPath = '/korrespond-tech.php';
$toolsLogin = 'https://dobetternorge.no/tools-login.php?return=' . urlencode('/korrespond.php');
$registerUrl = 'https://dobetternorge.no/register.php';
?>
<!doctype html>
<html lang="<?= htmlspecialchars($uiLang) ?>">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>How Korrespond works Hard-RAG, fine-tuned LLM, 3-pass pipeline</title>
<meta name="description" content="Technical deep-dive: how Korrespond uses Hard-RAG retrieval, a QLoRA fine-tuned legal LLM, and a 3-pass pipeline to produce verified Norwegian legal correspondence.">
<meta name="robots" content="index, follow">
<link rel="canonical" href="https://tools.dobetternorge.no/korrespond-tech.php">
<meta property="og:title" content="How Korrespond works — Hard-RAG, fine-tuned LLM, 3-pass pipeline">
<meta property="og:description" content="220K+ passages, 8 corpus slices, Azure gpt-4o, citation verification, and a QLoRA fine-tune on Norwegian legal text.">
<meta name="theme-color" content="#00205B">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Crimson+Pro:wght@400;600;700&family=IBM+Plex+Sans:wght@400;500;600;700&family=IBM+Plex+Mono:wght@400;500&display=swap">
<link rel="stylesheet" href="assets/css/tools.css">
</head>
<body class="kdoc-page">
<header class="lt-nav">
<a href="https://dobetternorge.no" class="lt-nav__brand">
<picture>
<source srcset="assets/images/logo-header.webp" type="image/webp">
<img class="lt-nav__logo" src="assets/images/logo-header.png" alt="Do Better Norge" width="140" height="36" loading="eager">
</picture>
<span class="lt-nav__badge">Legal Tools</span>
</a>
<div class="lt-nav__right">
<nav class="shell-lang-switcher" aria-label="Language">
<?php foreach (dbnToolsSupportedLanguages() as $langCode): ?>
<a href="<?= htmlspecialchars($langPath . '?lang=' . $langCode) ?>" class="<?= $langCode === $uiLang ? 'is-active' : '' ?>"><?= htmlspecialchars(dbnToolsLanguageLabel($langCode)) ?></a>
<?php endforeach; ?>
</nav>
<?php if ($isAuthed): ?>
<a href="/korrespond.php" class="lt-nav__cta lt-nav__cta--enter">Open Korrespond &rarr;</a>
<?php else: ?>
<a href="<?= htmlspecialchars($toolsLogin) ?>" class="lt-nav__cta">Sign in</a>
<?php endif; ?>
</div>
</header>
<nav class="kdoc-doc-nav" aria-label="Korrespond documentation">
<div class="kdoc-doc-nav__inner">
<a href="/korrespond-about.php">About</a>
<a href="/korrespond-guide.php">User guide</a>
<a href="/korrespond-tech.php" class="is-active">How it works</a>
<?php if ($isAuthed): ?><a href="/korrespond.php">&larr; Open the tool</a><?php endif; ?>
</div>
</nav>
<!-- Hero -->
<section class="kdoc-hero" style="background: linear-gradient(rgba(5,15,40,0.85),rgba(5,15,40,0.92)), url('assets/images/korrespond/hero-tech.png') center/cover no-repeat;">
<div class="kdoc-hero__inner">
<p class="kdoc-hero__kicker">Technical Showcase &middot; Hard-RAG &middot; Fine-tuned LLM &middot; 3-pass pipeline</p>
<h1 class="kdoc-hero__title">How Korrespond knows what to write.</h1>
<p class="kdoc-hero__sub">A full walkthrough of the retrieval-augmented generation pipeline, citation verification system, fine-tuned legal model, and the formal citation refine pass that produces court-ready references.</p>
<div class="kdoc-hero__stats">
<div class="kdoc-hero__stat">
<strong>220K+</strong>
<span>passages indexed</span>
</div>
<div class="kdoc-hero__stat">
<strong>8</strong>
<span>corpus slices</span>
</div>
<div class="kdoc-hero__stat">
<strong>3</strong>
<span>pipeline passes</span>
</div>
<div class="kdoc-hero__stat">
<strong>gpt-4o</strong>
<span>drafting model</span>
</div>
</div>
</div>
</section>
<!-- Architecture overview -->
<div class="kdoc-section">
<p class="kdoc-section__eyebrow">Architecture</p>
<h2 class="kdoc-section__title">Three passes. Each with a distinct job.</h2>
<p class="kdoc-section__sub">The pipeline is intentionally sequential Pass 1 is cheap and fast (gpt-4o-mini); Pass 2 is expensive and only runs if the situation is clear enough; Pass 3 is optional and user-triggered.</p>
<div class="kdoc-pipeline">
<div class="kdoc-pipeline__pass">
<span class="kdoc-pipeline__pass-badge kdoc-pipeline__pass-badge--mini">Pass 1 · gpt-4o-mini</span>
<h3 class="kdoc-pipeline__pass-title">Classify &amp; gap-check</h3>
<p class="kdoc-pipeline__pass-body">Parses the intake and returns a structured JSON classification:</p>
<ul>
<li><code>summary</code> one-sentence case summary</li>
<li><code>parties</code> identified actors</li>
<li><code>applicable_acts</code> relevant statute sets</li>
<li><code>missing_facts[]</code> gaps that would hurt draft quality</li>
<li><code>suggested_goal</code> inferred goal if none stated</li>
</ul>
<p class="kdoc-pipeline__pass-body" style="margin-top:0.7rem;">If <code>missing_facts</code> is non-empty emits <strong>clarify gate</strong>. No credit deducted until Pass 2 starts.</p>
</div>
<div class="kdoc-pipeline__arrow-down" aria-hidden="true">&rarr;</div>
<div class="kdoc-pipeline__pass">
<span class="kdoc-pipeline__pass-badge">Pass 2 · gpt-4o</span>
<h3 class="kdoc-pipeline__pass-title">Retrieve draft check translate</h3>
<p class="kdoc-pipeline__pass-body">Four sub-steps, each verified before proceeding:</p>
<ul>
<li><strong>Retrieve:</strong> hybrid dense + BM25 search across the preset corpus slices; top 8 passages returned with source IDs</li>
<li><strong>Draft:</strong> gpt-4o generates the letter using <code>[CITE:N]</code> tokens referencing only retrieved source IDs</li>
<li><strong>Self-check:</strong> strips any <code>[CITE:N]</code> token whose source ID isn't in the retrieved pool; flags deadline/goal/tone compliance</li>
<li><strong>Translate:</strong> Norwegian draft working language (single call)</li>
</ul>
</div>
<div class="kdoc-pipeline__arrow-down" aria-hidden="true">&rarr;</div>
<div class="kdoc-pipeline__pass">
<span class="kdoc-pipeline__pass-badge kdoc-pipeline__pass-badge--optional">Pass 3 · optional</span>
<h3 class="kdoc-pipeline__pass-title">Formal citation refine</h3>
<p class="kdoc-pipeline__pass-body">User-triggered (+1 credit). Jurisdiction-scoped retrieval, then rewrites inline citations to formal style and appends Rettskilder block:</p>
<ul>
<li><strong>Norwegian:</strong> <em>jf. forvaltningsloven § 17</em></li>
<li><strong>ECHR:</strong> full case name, application number, date, paragraph</li>
<li><strong>Both:</strong> combined domestic + ECHR grounds</li>
</ul>
</div>
</div>
</div>
<!-- Hard-RAG retrieval -->
<section class="kdoc-section--alt">
<div class="kdoc-section">
<p class="kdoc-section__eyebrow">Hard-RAG</p>
<h2 class="kdoc-section__title">Every § citation is verified before it reaches you.</h2>
<p class="kdoc-section__sub">Hard-RAG means the model is constrained to only cite what it retrieved. No § number can appear in the final draft unless a corresponding source passage was actually found and fetched.</p>
<div class="kdoc-rag-flow">
<div class="kdoc-rag-row">
<div class="kdoc-rag-box kdoc-rag-box--blue">User intake + body preset</div>
<span class="kdoc-rag-arrow">&rarr;</span>
<div class="kdoc-rag-box">Corpus slice selection</div>
<span class="kdoc-rag-arrow">&rarr;</span>
<div class="kdoc-rag-box">Hybrid search (dense vector + BM25)</div>
<span class="kdoc-rag-arrow">&rarr;</span>
<div class="kdoc-rag-box kdoc-rag-box--teal">Top 8 passages with source IDs</div>
</div>
<div class="kdoc-rag-row" style="margin-top:8px;">
<div class="kdoc-rag-box kdoc-rag-box--teal">Passages injected into gpt-4o prompt</div>
<span class="kdoc-rag-arrow">&rarr;</span>
<div class="kdoc-rag-box">Draft with [CITE:N] tokens only</div>
<span class="kdoc-rag-arrow">&rarr;</span>
<div class="kdoc-rag-box">Self-check: verify each [CITE:N] resolves</div>
<span class="kdoc-rag-arrow">&rarr;</span>
<div class="kdoc-rag-box kdoc-rag-box--red">Strip unverified citations</div>
</div>
</div>
<p style="font-size:0.9rem; line-height:1.7; margin-top:1.5rem; opacity:0.85;">The self-check pass parses every <code>[CITE:N]</code> token in the draft and looks up the source ID <code>N</code> in the retrieved pool. If it doesn't match the citation is removed and the paragraph is rewritten without it. The output also flags whether the deadline was addressed, whether the stated goal was achieved, and whether the tone matched the selected chip.</p>
<h3 style="font-family:'Crimson Pro',serif; font-size:1.2rem; font-weight:700; margin:2rem 0 0.8rem; color:var(--dbn-blue);">What happens when no statute fits?</h3>
<p style="font-size:0.9rem; line-height:1.7; opacity:0.85;">If no corpus passage closely matches the situation, the draft is produced in plain language without § references. A note in the output says: <em>"No cited law sources — draft is plain-language (no § references available from corpus)."</em> This is the intentional, honest behaviour a blank draft is better than one with fake citations.</p>
</div>
</section>
<!-- Knowledge base -->
<div class="kdoc-section">
<p class="kdoc-section__eyebrow">Knowledge base</p>
<h2 class="kdoc-section__title">220,000+ passages across 8 corpus slices.</h2>
<p class="kdoc-section__sub">The legal corpus is split into named slices. Each recipient body preset maps to a set of slices, so retrieval is always scoped to the right area of law.</p>
<div class="kdoc-kb-stats">
<div class="kdoc-kb-stat">
<strong>220K+</strong>
<span>total indexed passages</span>
</div>
<div class="kdoc-kb-stat">
<strong>8</strong>
<span>corpus slices</span>
</div>
<div class="kdoc-kb-stat">
<strong>1,731</strong>
<span>FNV tribunal decisions</span>
</div>
<div class="kdoc-kb-stat">
<strong>23</strong>
<span>ECHR Norwegian-family cases</span>
</div>
<div class="kdoc-kb-stat">
<strong>Azure</strong>
<span>AI Search (West Europe)</span>
</div>
<div class="kdoc-kb-stat">
<strong>Hybrid</strong>
<span>dense vector + BM25</span>
</div>
</div>
<h3 style="font-family:'Crimson Pro',serif; font-size:1.15rem; font-weight:700; margin:2rem 0 0.8rem; color:var(--dbn-blue);">Corpus slices</h3>
<div class="kdoc-slice-grid">
<span class="kdoc-slice-chip">child_welfare</span>
<span class="kdoc-slice-chip">echr</span>
<span class="kdoc-slice-chip">family_core</span>
<span class="kdoc-slice-chip">bufdir_guidance</span>
<span class="kdoc-slice-chip">norwegian_courts</span>
<span class="kdoc-slice-chip">broader_legal</span>
<span class="kdoc-slice-chip">dbn_resources</span>
<span class="kdoc-slice-chip">hague</span>
</div>
<h3 style="font-family:'Crimson Pro',serif; font-size:1.15rem; font-weight:700; margin:2rem 0 0.8rem; color:var(--dbn-blue);">Body preset slice mapping (examples)</h3>
<table class="kdoc-table">
<thead>
<tr><th>Recipient body</th><th>Corpus slices loaded</th></tr>
</thead>
<tbody>
<tr><td>Barnevernet</td><td>child_welfare · echr · family_core</td></tr>
<tr><td>Bufdir</td><td>family_core · echr · bufdir_guidance</td></tr>
<tr><td>NAV</td><td>broader_legal (NAV-loven)</td></tr>
<tr><td>Skole / Barnehage / SFO</td><td>broader_legal (opplæringslova / barnehageloven)</td></tr>
<tr><td>Statsforvalteren</td><td>child_welfare · broader_legal</td></tr>
<tr><td>Trygderetten / Tingretten</td><td>norwegian_courts · broader_legal</td></tr>
</tbody>
</table>
</div>
<!-- Fine-tuned LLM -->
<section class="kdoc-section--alt">
<div class="kdoc-section">
<p class="kdoc-section__eyebrow">Fine-tuned model</p>
<h2 class="kdoc-section__title">dbn-legal-agent: trained on Norwegian legal text.</h2>
<div class="kdoc-finetune">
<span class="kdoc-finetune__badge">QLoRA fine-tune</span>
<h3 class="kdoc-finetune__title">dbn-legal-agent</h3>
<p class="kdoc-finetune__body">A QLoRA (Quantized Low-Rank Adaptation) fine-tune trained on Norwegian child-welfare and administrative law text. Unlike a general-purpose LLM, dbn-legal-agent has internalized the procedural vocabulary and reasoning patterns of forvaltningsloven: what triggers a § 17 right to be heard, what a lawful § 24 reasoned decision must contain, how barnevernsloven § 6-3 frames the child's best interest standard.</p>
<p class="kdoc-finetune__body" style="margin-top:0.8rem;">In the Korrespond pipeline, dbn-legal-agent runs as a domain adapter alongside Azure gpt-4o. The retrieval prompt is constructed using dbn-legal-agent's representation of the intake, while gpt-4o handles the final generation within the Hard-RAG constraint. This separation gives structural clarity (gpt-4o) and domain precision (dbn-legal-agent) in the same pipeline.</p>
<div class="kdoc-finetune__chips">
<span class="kdoc-finetune__chip">QLoRA</span>
<span class="kdoc-finetune__chip">forvaltningsloven</span>
<span class="kdoc-finetune__chip">barnevernsloven</span>
<span class="kdoc-finetune__chip">child-welfare corpus</span>
<span class="kdoc-finetune__chip">Norwegian bokmål output</span>
<span class="kdoc-finetune__chip">gpt-4o co-pipeline</span>
</div>
</div>
<h3 style="font-family:'Crimson Pro',serif; font-size:1.15rem; font-weight:700; margin:2rem 0 0.8rem; color:var(--dbn-blue);">Model responsibilities in the pipeline</h3>
<table class="kdoc-table">
<thead>
<tr><th>Pass</th><th>Model</th><th>Role</th></tr>
</thead>
<tbody>
<tr><td>Pass 1 classify</td><td>gpt-4o-mini</td><td>Fast structured classification + gap detection</td></tr>
<tr><td>Pass 1 clarify questions</td><td>gpt-4o-mini + dbn-legal-agent</td><td>Domain-aware question generation</td></tr>
<tr><td>Pass 2 draft</td><td>gpt-4o</td><td>Full letter generation within Hard-RAG constraints</td></tr>
<tr><td>Pass 2 self-check</td><td>gpt-4o-mini</td><td>Citation verification + tone/goal/deadline audit</td></tr>
<tr><td>Pass 2 translate</td><td>gpt-4o-mini</td><td>Norwegian working language translation</td></tr>
<tr><td>Pass 3 refine</td><td>gpt-4o</td><td>Formal citation rewrite + Rettskilder block</td></tr>
</tbody>
</table>
</div>
</section>
<!-- Pass 3 formal citations -->
<div class="kdoc-section">
<p class="kdoc-section__eyebrow">Pass 3 Formal citation refine</p>
<h2 class="kdoc-section__title">Court-ready citations in two styles.</h2>
<p class="kdoc-section__sub">The optional third pass does a jurisdiction-scoped retrieval run, then rewrites the draft with formal inline citations and a Rettskilder appendix. Two distinct citation formats are supported:</p>
<div class="kdoc-features" style="margin-bottom:2rem;">
<div class="kdoc-feature-card">
<span class="kdoc-feature-card__icon">&#127475;&#127476;</span>
<h3 class="kdoc-feature-card__title">Norwegian statute style</h3>
<p class="kdoc-feature-card__body">Inline citations use <em>jf.</em> (with reference to) and the official statute name + section: <code>jf. forvaltningsloven § 17</code>, <code>jf. opplæringslova § 9 A-4</code>, <code>jf. barnevernsloven § 6-3</code>. Section numbers are verified against the corpus before inclusion.</p>
</div>
<div class="kdoc-feature-card">
<span class="kdoc-feature-card__icon">&#9878;&#65039;</span>
<h3 class="kdoc-feature-card__title">ECHR citation style</h3>
<p class="kdoc-feature-card__body">Full European Court of Human Rights citation format: case name · application number · date · chamber/Grand Chamber · paragraph. Example: <code>Strand Lobben m.fl. mot Norge, EMD-37283/13 (Storkammer, 10.09.2019), § 207</code>. Sources pulled from the ECHR corpus slice and HUDOC.</p>
</div>
</div>
<h3 style="font-family:'Crimson Pro',serif; font-size:1.15rem; font-weight:700; margin:0 0 0.8rem; color:var(--dbn-blue);">Example refined output</h3>
<img src="assets/images/korrespond/output-refined.png" alt="Refined output showing formal citations including opplæringslova §9 A-4 and EMK artikkel 8" class="kdoc-screenshot" style="max-width:800px; display:block;" loading="lazy">
<p style="font-size:0.82rem; opacity:0.65; text-align:center; margin-top:0.5rem;">Refined draft (Norwegian + English) with <em>opplæringslova § 9 A-4</em> and <em>EMK artikkel 8</em> inline citations.</p>
<h3 style="font-family:'Crimson Pro',serif; font-size:1.15rem; font-weight:700; margin:2rem 0 0.8rem; color:var(--dbn-blue);">Anchor queries for ECHR mode</h3>
<p style="font-size:0.9rem; line-height:1.7; opacity:0.85; margin-bottom:1rem;">For Barnevernet and Bufdir cases, the ECHR refine pass runs specific anchor queries targeting the most-cited Norwegian family cases in the HUDOC corpus:</p>
<div class="kdoc-slice-grid">
<span class="kdoc-slice-chip">Strand Lobben m.fl. mot Norge</span>
<span class="kdoc-slice-chip">Johansen mot Norge</span>
<span class="kdoc-slice-chip">K.O. og V.M. mot Norge</span>
<span class="kdoc-slice-chip">Aune mot Norge</span>
<span class="kdoc-slice-chip">EMK Art. 8 family life Norway</span>
<span class="kdoc-slice-chip">EMK Art. 6 fair trial</span>
</div>
</div>
<!-- Privacy by design -->
<section class="kdoc-section--alt">
<div class="kdoc-section">
<p class="kdoc-section__eyebrow">Privacy &amp; security</p>
<h2 class="kdoc-section__title">Your documents never leave your session.</h2>
<div class="kdoc-privacy">
<p class="kdoc-privacy__title">Privacy by design</p>
<ul>
<li>All uploaded files are extracted to text <strong>in memory</strong> using PHP's in-process file handlers. The raw binary is never written to disk on the server.</li>
<li>Session context (your narrative, uploaded text, drafts) is scoped to your authenticated session and discarded when the session ends.</li>
<li>Azure OpenAI (gpt-4o, gpt-4o-mini) is configured on the <strong>West Europe</strong> region. Data processed via Azure OpenAI is not used for model training under the default enterprise agreement.</li>
<li>Azure AI Search (<code>bnl-legal-search</code>) stores <strong>only the public legal corpus</strong> statutes, tribunal decisions, ECHR judgments. None of your case information is stored in the search index.</li>
<li>Qdrant vector database stores only the public corpus embeddings no user data.</li>
<li>Telemetry logged: tool name, language, output type, pass count, latency, source count. <strong>No case text, no names, no case references are logged.</strong></li>
</ul>
</div>
</div>
</section>
<!-- CTA -->
<section class="kdoc-cta-strip">
<h2 class="kdoc-cta-strip__title">See it work on your case.</h2>
<p class="kdoc-cta-strip__sub">Free for Do Better Norge members. All 3 passes available to every member.</p>
<div class="kdoc-hero__ctas">
<?php if ($isAuthed): ?>
<a href="/korrespond.php" class="kdoc-btn-primary">Open Korrespond &rarr;</a>
<?php else: ?>
<a href="<?= htmlspecialchars($toolsLogin) ?>" class="kdoc-btn-primary">Sign in to use Korrespond &rarr;</a>
<a href="<?= htmlspecialchars($registerUrl) ?>" class="kdoc-btn-secondary">Register free</a>
<?php endif; ?>
<a href="/korrespond-guide.php" class="kdoc-btn-secondary">User guide</a>
</div>
</section>
<?php require_once __DIR__ . '/includes/footer.php'; ?>
<script src="assets/js/tools.js" defer></script>
</body>
</html>
+8
View File
@@ -16,6 +16,14 @@ require_once __DIR__ . '/includes/layout.php';
<button type="button" class="lang-btn" data-lang="pl">&#127477;&#127473; PL</button> <button type="button" class="lang-btn" data-lang="pl">&#127477;&#127473; PL</button>
</div> </div>
<div class="korr-doc-links">
<a href="/korrespond-about.php" target="_blank">About this tool</a>
<span aria-hidden="true">&middot;</span>
<a href="/korrespond-guide.php" target="_blank">User guide</a>
<span aria-hidden="true">&middot;</span>
<a href="/korrespond-tech.php" target="_blank">How it works</a>
</div>
<!-- Mode toggle --> <!-- Mode toggle -->
<div class="control-row" id="korrModeControl"> <div class="control-row" id="korrModeControl">
<span class="control-label">Mode</span> <span class="control-label">Mode</span>
+71
View File
@@ -91,6 +91,18 @@ $localizedContent = [
'Per-slice document browser with source count and last-indexed date', 'Per-slice document browser with source count and last-indexed date',
], ],
], ],
'korrespond' => [
'pitch' => 'Describe your situation — the authority, what happened, your goal — and Korrespond retrieves the applicable statutes from 220,000+ indexed legal passages, drafts a formal letter in Norwegian bokmål, verifies every § citation against what it actually retrieved, and returns the draft side-by-side with your working language. Optional second pass rewrites with court-ready formal citations (jf. forvaltningsloven § 17, Strand Lobben m.fl. mot Norge § 207) and a Rettskilder appendix.',
'features' => [
'3-pass pipeline: classify + gap-check → Hard-RAG draft + self-check → optional formal-citation refine',
'11 authority presets (Barnevernet, NAV, skole, Bufdir, Statsforvalter, Trygderetten…) each pre-loading the right statute set',
'Hard-RAG: every § citation verified against retrieved corpus — no fake references, ever',
'Always outputs Norwegian bokmål (canonical) + your working language (EN/PL/UK) side-by-side',
'Optional Refine pass: Norwegian statute style (jf. fvl § 17) or ECHR with full case name + paragraph',
'Powered by dbn-legal-agent — a QLoRA fine-tune on Norwegian child-welfare and administrative law',
],
],
], ],
'no' => [ 'no' => [
@@ -164,6 +176,18 @@ $localizedContent = [
'Utsnittleser med dokumentantall og sist-indeksert-dato', 'Utsnittleser med dokumentantall og sist-indeksert-dato',
], ],
], ],
'korrespond' => [
'pitch' => 'Beskriv situasjonen — mottaker, hva som skjedde, og hva du vil oppnå — og Korrespond henter relevante lovbestemmelser fra over 220 000 indekserte juridiske passasjer, skriver et formelt brev på norsk bokmål, verifiserer alle §-henvisninger mot faktisk hentet materiale, og leverer utkastet side om side med ditt arbeidsspråk. Valgfri andreskanning gir rettssikre sitater (jf. forvaltningsloven § 17, Strand Lobben m.fl. mot Norge § 207) og et Rettskilder-vedlegg.',
'features' => [
'3-trinns pipeline: klassifiser + mangelsjekk → Hard-RAG-utkast + selvsjekk → valgfri sitatforbedring',
'11 mottakerforhåndsinnstillinger (Barnevernet, NAV, skole, Bufdir, Statsforvalter, Trygderetten…)',
'Hard-RAG: alle §-sitater verifisert mot hentet korpus — ingen falske referanser',
'Alltid norsk bokmål (kanonisk) + arbeidsspråket ditt (EN/PL/UK) side om side',
'Valgfri refinering: norsk lovstil (jf. fvl § 17) eller EMD med fullt saksnavn + avsnitt',
'Drevet av dbn-legal-agent — QLoRA-finjustert på norsk barnevernsrett og forvaltningsrett',
],
],
], ],
]; ];
@@ -405,6 +429,44 @@ $samples = [
'p95 latency : 142 ms', 'p95 latency : 142 ms',
]), ]),
], ],
'korrespond' => [
'scenario_label' => ($uiLang === 'no') ? 'Situasjonsbeskrivelse' : 'Situation',
'scenario' => ($uiLang === 'no')
? 'Mottaker: Barnevernet &mdash; Modus: Initier &mdash; Mål: Be om tilgang til saksdokumenter &mdash; Tone: Fast'
: 'Recipient: Barnevernet &mdash; Mode: Initiate &mdash; Goal: Request access to case documents &mdash; Tone: Firm',
'output_label' => ($uiLang === 'no') ? 'Utkast (norsk bokmål)' : 'Draft (Norwegian bokmål)',
'output' => implode("\n", [
'KORRESPOND — Formelt brev',
'Mottaker: Barnevernet · Modus: Initier · Ton: Fast',
'Hentede lovkilder: 4 passasjer (fvl, barnevernsloven)',
'',
'Til: [Barnevernstjenesten, kommunenavn]',
'Fra: [Navn]',
'Dato: 19. mai 2026',
'Ref.: [Saksnummer]',
'',
'Anmodning om innsyn i saksdokumenter',
'─────────────────────────────────────',
'Jeg ber herved om innsyn i alle saksdokumenter',
'tilknyttet min sak, jf. forvaltningsloven § 18.',
'',
'Som part i saken har jeg rett til å gjøre meg',
'kjent med alle dokumenter i saken, med mindre',
'særlige unntak etter fvl. §§ 18 a-e gjør seg',
'gjeldende. Jeg ber om at slikt unntak begrunnes',
'skriftlig, jf. fvl. § 24-25.',
'',
'Jeg ber om svar innen 5 virkedager.',
'',
'Med vennlig hilsen,',
'[Navn]',
'',
'─────────────────────────────────────',
'Siterte lovkilder: fvl. § 18 · fvl. § 24-25',
'Selvsjekk: mål oppfylt ✓ · frist nevnt ✓ · tone Fast ✓',
]),
],
]; ];
$sample = $samples[$slug]; $sample = $samples[$slug];
@@ -504,6 +566,15 @@ $sample = $samples[$slug];
<p class="lt-preview-cta__note"><?= htmlspecialchars(dbnToolsT('preview_free_note', $uiLang)) ?></p> <p class="lt-preview-cta__note"><?= htmlspecialchars(dbnToolsT('preview_free_note', $uiLang)) ?></p>
<a class="lt-preview-cta__btn" href="<?= htmlspecialchars($toolsLogin) ?>"><?= htmlspecialchars(dbnToolsT('preview_get_access', $uiLang)) ?> &rarr;</a> <a class="lt-preview-cta__btn" href="<?= htmlspecialchars($toolsLogin) ?>"><?= htmlspecialchars(dbnToolsT('preview_get_access', $uiLang)) ?> &rarr;</a>
<p class="lt-preview-cta__register"><a href="https://dobetternorge.no/register.php"><?= htmlspecialchars(dbnToolsT('preview_join', $uiLang)) ?></a></p> <p class="lt-preview-cta__register"><a href="https://dobetternorge.no/register.php"><?= htmlspecialchars(dbnToolsT('preview_join', $uiLang)) ?></a></p>
<?php if ($slug === 'korrespond'): ?>
<div style="margin-top:1.5rem; padding-top:1.5rem; border-top:1px solid rgba(255,255,255,0.15); display:flex; gap:1rem; flex-wrap:wrap; justify-content:center;">
<a href="/korrespond-about.php" style="color:#fff; opacity:0.85; font-size:0.88rem; text-decoration:none; border-bottom:1px solid rgba(255,255,255,0.4); padding-bottom:2px;">About Korrespond</a>
<span style="color:rgba(255,255,255,0.4);">&middot;</span>
<a href="/korrespond-guide.php" style="color:#fff; opacity:0.85; font-size:0.88rem; text-decoration:none; border-bottom:1px solid rgba(255,255,255,0.4); padding-bottom:2px;">User guide</a>
<span style="color:rgba(255,255,255,0.4);">&middot;</span>
<a href="/korrespond-tech.php" style="color:#fff; opacity:0.85; font-size:0.88rem; text-decoration:none; border-bottom:1px solid rgba(255,255,255,0.4); padding-bottom:2px;">How it works</a>
</div>
<?php endif; ?>
</div> </div>
<div class="lt-preview-cta__tools"> <div class="lt-preview-cta__tools">
<p class="lt-preview-cta__tools-label"><?= htmlspecialchars(dbnToolsT('preview_other_tools', $uiLang)) ?></p> <p class="lt-preview-cta__tools-label"><?= htmlspecialchars(dbnToolsT('preview_other_tools', $uiLang)) ?></p>