# Sundsvall DS – regler för AI-agenter och utvecklare

Detta dokument läses av AI-verktyg (Claude Code, Cursor, Copilot m.fl.) innan de genererar gränssnitt för Sundsvalls kommun. Reglerna är skrivna som påståenden som går att kontrollera. Källa för alla värden: `tokens.json`. Komponenter: shadcn/ui via kommunens registry.

## 1. Grundkontrakt

- Stack: React, Tailwind v4, shadcn/ui. Installera komponenter med `npx shadcn@latest add https://ds.sundsvall.dev/r/<namn>.json`. Använd aldrig upstream-shadcn direkt.
- Använd endast semantiska tokens (`bg-background`, `text-foreground`, `bg-primary`, `border-border`, `text-muted-foreground`, `bg-success-soft` …). Skriv aldrig hex, rgb, oklch eller Tailwinds standardfärger (`bg-blue-600`, `text-gray-500`) i komponentkod. Lint stoppar bygget.
- Primitiva skalor (`--vattjom-600`, `--neutral-300` …) får bara användas i `globals.css` och i diagram (`chart-1..5`). Aldrig i komponenter.
- Verksamhetstema sätts en gång per tjänst med `data-brand` på `<html>`: `vattjom` (standard), `gronsta`, `bjornstigen`, `juniskar`. Byt aldrig tema inne i en tjänst; en tjänst har en färg.
- Mörkt läge följer `prefers-color-scheme` automatiskt. Skriv aldrig `dark:`-varianter för färg; tokens hanterar det.

## 2. Ytor och djup (motverkar platthet)

Sidan byggs i lager. Varje lager har ett eget token och en egen elevation:

| Lager | Token | Elevation | Används till |
|---|---|---|---|
| Bakgrund | `bg-background` | – | sidans grund |
| Yta | `bg-surface` / `bg-card` | `shadow-elevation-1` | kort, paneler, formulärsektioner |
| Upphöjd yta | `bg-surface-raised` | `shadow-elevation-2` | popover, dropdown, meny |
| Dialog | `bg-surface-raised` | `shadow-elevation-3` | dialog, sheet, drawer |
| Nedsänkt | `bg-surface-sunken` | – | kodblock, sammanfattningar, inaktiva områden |

- Kort ligger alltid på `bg-background`, aldrig på annat kort. Max två nivåer av nästling.
- Kanter: `border-border` för avgränsning, `border-input` för fält. Inga andra kantfärger.
- Radie följer hierarki: `rounded-sm` chips/tabellkontroller, `rounded-md` knappar/fält, `rounded-lg` kort, `rounded-xl` dialoger. Använd inte samma radie på allt.
- Skuggor är tonade i mörkblått (`--shadow-color`), aldrig ren svart i ljust läge.

## 3. Färgens betydelse

- `primary` = handling. En primärknapp per vy. Sekundära handlingar: `variant="secondary"` eller `variant="outline"`.
- `success`, `info`, `warning`, `destructive` = status, aldrig dekoration. Använd alltid `*-soft` som bakgrund och `*-soft-foreground` som text för meddelanden; den mättade tonen används bara för ikoner, kanter och små indikatorer.
- Färg är aldrig ensam bärare av betydelse. Status har alltid ikon eller text.
- Verksamhetsfärgen dominerar: max ~10 % av ytan är mättad färg. Resten är neutral.

## 4. Typografi och rytm

- UI-text: `font-sans` (Inter). Rubriker nivå 1–2 i tjänster: `font-display` (Raleway, bold). Kod/ärendenummer: `font-mono`.
- Skala: `text-sm` (14) för hjälptext och tabeller, `text-base` (16) för brödtext och fält, `text-lg`/`text-xl` för sektionsrubriker, `text-3xl` för sidrubrik. Aldrig under 12 px.
- Radlängd max 70 tecken för brödtext (`max-w-prose`).
- Avstånd: 4 px-skalan. Inom komponent 8–12, mellan fält 16–24, mellan sektioner 32–48.
- Ingen text i versaler. Ingen text i kursiv för betoning i gränssnitt.

## 5. Tillgänglighet (WCAG 2.2 AA, lagkrav)

- Ingen information bärs av en ljus ton ensam. Mjuka ytor (`bg-*-soft`) har alltid `border-*-soft-border` och en ikon eller text; kort har alltid kant (`shadow-elevation-*` bär kanten). Anledning: TV-apparater, projektorer och solljus klipper bort toner under ~1.3:1.
- Intilliggande ytor skiljer ≥ 1.18:1 och separeras av kant ≥ 2:1. Fältkanter ≥ 3:1. Egna ljusare toner (steg 50–100 som bakgrund) är inte tillåtna i komponenter.
- Högkontrastläge: `data-contrast="high"` på `<html>`, eller automatiskt via `prefers-contrast: more`. Skriv aldrig egna högkontrastregler i komponenter; tokens hanterar det. Testa varje vy i det läget innan leverans.

- Kontrast: text ≥ 4.5:1, stor text och gränssnittskomponenter ≥ 3:1. Alla token-par i `tokens.json` är förberäknade; egna par är inte tillåtna.
- Fokus: synlig ring (`ring`) på alla interaktiva element. Ta aldrig bort `outline` utan ersättning.
- Måltyta minst 24×24 px, knappar 44 px höga på mobil.
- Formulär: varje fält har synlig `<Label>`, felmeddelande kopplat med `aria-describedby`, felet står vid fältet och sammanfattas överst.
- Språk: `lang="sv"` på dokumentet. Klarspråk. Skriv "du", inte "användaren".

## 6. Mönster (bygg med dessa, hitta inte på egna)

Namngivna block i registryt. Beskriv alltid en vy med mönsternamn innan kod skrivs.

- `service-header` – tjänstens rubrik, kort beskrivning, vem som kan använda den, inloggning.
- `step-form` – flerstegsformulär med stegindikator, "Spara och fortsätt senare", sammanfattning innan inskick.
- `case-status` – ärendestatus med tidslinje (mottaget → handläggs → beslut).
- `summary-card` – nedsänkt sammanfattning med "Ändra"-länkar per sektion.
- `notice` – meddelande (info/success/warning/destructive) med ikon, rubrik, text, valfri åtgärd.
- `personal-data-notice` – standardtext om personuppgiftsbehandling, alltid före inskick.
- `empty-state` – tom vy med förklaring och en primär handling.
- `data-table` – tabell med sortering, filter, radval; aldrig fler än 7 kolumner utan att gömma sekundära.

## 7. Text i gränssnitt

- Knappar säger vad som händer: "Skicka in ansökan", inte "Skicka". Samma verb hela vägen: knappen "Spara" ger toasten "Sparat".
- Fel förklarar vad som hände och vad man gör: "Personnumret behöver vara 12 siffror (ÅÅÅÅMMDDXXXX)". Aldrig "Ogiltig inmatning".
- Tomma vyer bjuder in till handling, de beklagar sig inte.
- Datum: `16 september 2026`. Belopp: `1 250 kr`. Ärendenummer i `font-mono`.

## 8. Innan du levererar (checklista agenten kör själv)

1. Grep: inga hex/rgb/oklch/`bg-<tailwindfärg>` i `src/`.
2. Byt `data-brand` till alla fyra värden, `data-theme` till `dark` och `data-contrast` till `high` – allt ska hålla.
3. Kör `pnpm lint` (stylelint + eslint-plugin-sundsvall) och `pnpm test:a11y` (axe).
4. Varje vy använder minst ett namngivet mönster från §6.
5. Exakt en primärknapp per vy.

## 9. Kända gap (kräver beslut av kommunikationsavdelningen)

- Profilen saknar en varningsfärg (orange/gul). Förslaget lägger till `warning` som funktionellt tillägg utanför profilen. Tills beslut finns: använd `info` med ikon.
- `destructive` bygger på Juniskär (rosa) i stället för klassiskt rött. Testat mot AA; utvärdera igenkänning med användare.
