/* Modernist — design-system tokens and component classes. This file is the source of truth for the system's look; retune it here and see readme.md. */
/* Skriftene lastes her fra en hostet kilde, så tegningene i dette prosjektet
   viser riktig skrift. VED HANDOFF: skriftene skal leveres fra repoet, ikke
   fra en tredjepart. Bytt @import-linjen under mot blokken som står i
   kommentar, og legg de to variable font-filene i fonts/.

   @font-face {
     font-family: 'Public Sans';
     src: url('fonts/PublicSans-Variable.woff2') format('woff2-variations');
     font-weight: 400 700; font-style: normal; font-display: swap;
   }
   @font-face {
     font-family: 'Newsreader';
     src: url('fonts/Newsreader-Variable.woff2') format('woff2-variations');
     font-weight: 400 600; font-style: normal; font-display: swap;
   }
*/
@import url('https://fonts.googleapis.com/css2?family=Public+Sans:wght@400;500;600;700&family=Newsreader:opsz,wght@6..72,400;6..72,500;6..72,600&display=swap');

/* Den lyse paletten henger på BEGGE: roten, og et undertre som sier at det er lyst.
   Uten det andre leddet arver en lys drakt inne i siden de mørke verdiene den dagen
   maskinen står i mørk modus — `:not([data-drakt="lys"])` beskytter elementet regelen
   treffer, aldri etterkommerne. Tegningene våre viser lys og mørk side om side, så
   dette er ikke et kanttilfelle her; det er hovedtilfellet. */
:root, [data-drakt="lys"] {
  --color-bg: #eae6de;
  --color-surface: #fbfaf7;
  --color-text: #1b1a17;
  --color-accent: #3d6b53;
  --color-accent-2: #a9694a;
  --color-divider: #ddd7cb;

  /* Feltkant og dempet tekst har egne tokens fordi de har egne krav:
     feltkanten må nå 3:1 mot BÅDE feltets egen flate og flaten rundt,
     dempet tekst må nå 4,5:1 mot begge. Å tone ned med en prosent
     overlever ikke at bakgrunnen snus — derfor målte trinn, ikke color-mix. */
  --color-field-border: #6d675d;  /* 5,4:1 mot surface · 4,5:1 mot bg */
  --color-text-muted: #625c53;    /* 6,4:1 mot surface · 5,4:1 mot bg */

  /* Tonal ramps — generated in OKLCH on one shared lightness scale, so the
     same step of any role matches the others in visual value. */
  --color-neutral-100: #f9f7f2;
  --color-neutral-200: #e6e1d6;
  --color-neutral-300: #ddd7cb;
  --color-neutral-400: #c6bfb0;
  --color-neutral-500: #a8a193;
  --color-neutral-600: #8b8477;
  --color-neutral-700: #6d675d;
  --color-neutral-800: #4a453e;
  --color-neutral-900: #1b1a17;

  --color-accent-100: #eef4ef;
  --color-accent-200: #e0ebe3;
  --color-accent-300: #c2d8cb;
  --color-accent-400: #92b7a1;
  --color-accent-500: #5d8e72;
  --color-accent-600: #2c503d;
  --color-accent-700: #244232;
  --color-accent-800: #1b3126;
  --color-accent-900: #12211a;

  --color-accent-2-100: #fbf2ec;
  --color-accent-2-200: #f3e2d6;
  --color-accent-2-300: #e6c8b4;
  --color-accent-2-400: #d3a385;
  --color-accent-2-500: #bd7d5c;
  --color-accent-2-600: #a9694a;
  --color-accent-2-700: #8a5239;
  --color-accent-2-800: #653c2a;
  --color-accent-2-900: #40271c;

  --font-heading: "Newsreader", Georgia, serif;
  --font-heading-weight: 500;
  --font-body: "Public Sans", system-ui, sans-serif;

  --space-1: 4.0px;
  --space-2: 8.0px;
  --space-3: 12.0px;
  --space-4: 16.0px;
  --space-6: 24.0px;
  --space-8: 32.0px;

  --radius-sm: 7px;
  --radius-md: 9px;
  --radius-lg: 12px;

  /* Elevation — derived from the ground: soft ink-tinted shadows on a
     light theme, a hairline edge + ambient darkness on a dark one. */
  --shadow-sm: 0 1px 2px color-mix(in srgb, #2f2d27 8%, transparent);
  --shadow-md: 0 2px 8px color-mix(in srgb, #2f2d27 10%, transparent);
  --shadow-lg: 0 10px 28px color-mix(in srgb, #2f2d27 14%, transparent);
}

/* ── Mørk drakt ────────────────────────────────────────────────────────────
   Settes med data-drakt="mork" på et hvilket som helst element; alt innenfor
   arver. Brukes av admin.gusto.no, mørke sidefoter og mørke blokker på
   kundesider. Tegnet i «Mork drakt.dc.html» (27). Verdiene er ikke en
   invertering av den lyse — flatene er varmere og kontrasten lavere, ellers
   flimrer teksten. */
[data-drakt="mork"] {
  --color-bg: #1b1a17;
  --color-surface: #26241f;
  --color-text: #f7f5f0;
  --color-divider: #3a362f;
  --color-field-border: #8b8477;  /* 4,2:1 mot surface · 4,7:1 mot bg */
  --color-text-muted: #b3ada1;    /* 7,0:1 mot surface · 8,1:1 mot bg */
  --color-accent: #9dc4ac;
  --color-accent-2: #d3a385;

  --color-neutral-100: #26241f;
  --color-neutral-200: #302d27;
  --color-neutral-300: #3a362f;
  --color-neutral-400: #4a463f;
  --color-neutral-500: #6d675d;
  --color-neutral-600: #8b8477;
  --color-neutral-700: #a8a193;
  --color-neutral-800: #cfc8ba;
  --color-neutral-900: #f7f5f0;

  --color-accent-100: #22302a;
  --color-accent-200: #2b3f35;
  --color-accent-300: #3a5748;
  --color-accent-400: #5d8e72;
  --color-accent-500: #7fae91;
  --color-accent-600: #b4d4c0;
  --color-accent-700: #cbe2d4;
  --color-accent-800: #e2f0e8;
  --color-accent-900: #f2f8f4;

  --color-accent-2-100: #33251d;
  --color-accent-2-200: #432f24;
  --color-accent-2-300: #5c4131;
  --color-accent-2-400: #8a5239;
  --color-accent-2-500: #bd7d5c;
  --color-accent-2-600: #d3a385;
  --color-accent-2-700: #e2bfa8;
  --color-accent-2-800: #f0d9c8;
  --color-accent-2-900: #f8ece2;

  /* På mørk flate bærer ikke skygge. Hevet flate markeres med en lysere
     kant, og skyggen holdes bare som ambient dybde under dialoger. */
  --shadow-sm: 0 0 0 1px #302d27;
  --shadow-md: 0 0 0 1px #3a362f, 0 4px 14px rgb(0 0 0 / 0.35);
  --shadow-lg: 0 0 0 1px #3a362f, 0 16px 40px rgb(0 0 0 / 0.5);
}

[data-drakt="mork"] { background: var(--color-bg); color: var(--color-text); }

/* OG DEN LYSE TRENGER DEN SAMME LINJEN. Funnet 22. august, i en kontroll av
   sju nye flater: tre overskrifter sto nær-hvite på lys flate, 1,03:1.

   Kommentaren over den lyse paletten sier at en lys drakt inne i en mørk side
   trenger sitt eget ledd for å få riktige TOKENS. Det var halve jobben:
   tokenene fulgte med, men `color` gjorde det ikke — den ble bare satt på
   `[data-drakt="mork"]`. **Følgen er at et element uten egen `color` inne i en
   lys øy på en mørk side arvet sidens nær-hvite tekst**, mens flaten under det
   var lys. Den var usynlig i ordets egentlige betydning.

   Feilformen er verdt å ha skrevet: **den ene drakta hadde en regel den andre
   ikke hadde, og asymmetrien så ut som ingenting** — helt til noen tegnet lys
   og mørk side om side i samme fil. Tegningene våre gjør nettopp det, hele
   tiden, så dette er hovedtilfellet og ikke et kanttilfelle.

   Den skal IKKE speiles i @media-blokka nederst: der er `[data-drakt="lys"]`
   allerede unntaket maskinvalget beskytter, og denne regelen treffer den øya
   uansett hvor drakta kom fra. */
[data-drakt="lys"] { background: var(--color-bg); color: var(--color-text); }

/* Primærknappen snur på mørk flate: lys aksent med mørk skrift.

   LYSVAKTEN — og den står i BEGGE dørene, med vilje.

   Drakta har to innganger: attributtet `[data-drakt="mork"]` (vi eller hun
   har bestemt det) og maskinvalget nederst i fila. **Vakten hører ikke til
   inngangen — den hører til øya.** En lys øy inne på en mørk side er lys
   uansett hvordan siden ble mørk, så unntaket må hoppe over den på begge
   veier inn. Sto den bare i én, ville regelen vært sann for drakta vi
   valgte og usann for drakta maskinen hennes valgte — og den siste er den
   ingen av oss ser.

   Tilfellet den fanger er hovedtilfellet her: tegningene setter lyse og
   mørke paneler side om side i samme fil, og en `.btn-primary` inne i en
   lys øy på en mørk side fikk mørk skrift på mørk aksent — **2,84:1**.

   Prøven er en telling og ikke et blikk: antallet regler som treffer
   `[data-drakt="mork"] X` skal være likt antallet `:root:not([data-drakt=
   "lys"]) X` nederst, og alle i begge settene skal bære `:not([data-drakt=
   "lys"] *)`. Den kan feile, og det er poenget.

   Grensen, skrevet fordi den er ekte: vakten ser ett nivå. En mørk øy
   nestet inne i en lys øy blir hoppet over av begge settene. Det finnes
   ikke i huset i dag; den dagen det gjør, er dette stedet å komme til.

   VEKTEN — vakten bæres av `:where()`, og det er ikke pynt. Bar veier
   `:not([data-drakt="lys"] *)` (0,2,0) i seg selv, og løfter regelen fra
   (0,2,0) til (0,4,0) — forbi `.btn:disabled`, som er (0,2,0). Da er den
   lyse øya reddet og den sperrede knappen ødelagt: 1,45:1, i begge veier.
   `:where()` endrer aldri hva en velger TREFFER, bare hva den er VERDT.
   Øya slipper unna akkurat like mye som før; regelen står på (0,2,0), der
   tvillingen står. Der står også `.btn:disabled` (0,2,0), på linje 581 —
   ETTER denne — så uavgjort avgjøres av kilderekkefølge, og den sperrede
   knappen vinner. Grønt, men det er rekkefølgen som holder det, ikke vekt.

   SPEILET SKRIVES `:where(:root:not(…))` OG IKKE `:root:where(:not(…))`.
   Målt av utvikleren 23. august over 47 tegninger: den første gir null
   avvik, den andre gir to. Grunnen er den samme linja 581 — speilet står
   på 1625, altså ETTER `.btn:disabled`, så et speil på (0,2,0) vinner
   uavgjort og gir mørk skrift på en sperret knapp. Formen her veier hele
   inngangen til null; speilet lander på (0,1,0) og taper da på vekt i
   stedet for på rekkefølge. **Likhet i vekt var aldri målet** — begge
   veier skal TAPE mot `.btn:disabled`, og bare denne ene gjør det av seg
   selv. Setningen om «samme vakt og samme vekt» er derfor rettet: samme
   vakt, ja. Samme vekt var en gjetning om hva som gjorde den grønn.

   Og de samme bytene måler grønt hos utvikleren uansett form, fordi
   `ShellStylesheet.Split` sender de to reglene til hvert sitt ark og
   ds-delene lenkes sist. **Feilen er bare synlig i tegningene.** Med denne
   formen er arket sant både der det leses og der det kjøres.

   Unntaket: grepet som veier en hel inngang til null skal IKKE på tokenblokkene eller
   bakgrunnsregelen i speilblokka. De må bli værende (0,2,0) for å slå
   `[data-drakt="lys"]` (0,1,0) over — senkes de, vinner maskinvalget på
   kilderekkefølge og lyse øyer blir mørke. */
[data-drakt="mork"] .btn-primary:where(:not([data-drakt="lys"] *)) { color: #1b1a17; }
[data-drakt="mork"] .btn-primary:hover:where(:not([data-drakt="lys"] *)) { background: var(--color-accent-600); }
[data-drakt="mork"] .btn-primary:active:where(:not([data-drakt="lys"] *)) { background: var(--color-accent-700); }
[data-drakt="mork"] .seg-opt:has(input:checked):where(:not([data-drakt="lys"] *)) { color: #1b1a17; }
[data-drakt="mork"] .radio input:checked + .dot:where(:not([data-drakt="lys"] *)) { box-shadow: inset 0 0 0 4px var(--color-bg); }

body {
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-body);
}
h1, h2, h3, h4 { font-family: var(--font-heading); font-weight: var(--font-heading-weight); }


/* ══════════════════════════════════════════════════════════════════════════
   Components — built with the tokens above. Plain CSS
   on plain HTML: no JavaScript, no build step. Each class is documented in
   readme.md and demonstrated in foundations/ and components/.
   ══════════════════════════════════════════════════════════════════════ */

*, *::before, *::after { box-sizing: border-box; }
/* 16 = --f3 etter runde 25. 15 sto her fra før skalaen flyttet trinnet, og
   etterslepet var den ene av de to ds.css-størrelsene i utviklerens måling
   24. august. Bygget var alt 16 — det er tegningene som kommer etter. */
body { margin: 0; font-size: 16px; line-height: 1.55; font-weight: 400; }
h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  line-height: 1.18; letter-spacing: -0.005em; margin: 0 0 var(--space-2);
}
h5, h6 { font-family: var(--font-body); font-weight: 600; }
h1 { font-size: 42px; }
h2 { font-size: 32px; }
h3 { font-size: 25px; }
h4 { font-size: 20px; }
h5 { font-size: 16px; }
h6 { font-size: 13px; }
h6 { letter-spacing: 0.08em; text-transform: uppercase; }
p { margin: 0 0 var(--space-3); }
a { color: var(--color-accent); text-underline-offset: 3px; }
img { display: block; max-width: 100%; }
figure { margin: 0; }
figcaption {
  font-size: 11px; margin-top: var(--space-1);
  color: var(--color-text-muted);
}
.text-muted { color: var(--color-text-muted); }
:focus { outline: none; }
:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }
/* MARKERT TEKST · svar til bygget 23. august. Verdien sto her fra før; det som
   manglet var at `grunn.css` ikke mapper den, så Picos blå gikk rett gjennom.
   **Verdien er ikke ny — den er denne, og den er nå målt.**

   Aksent på 30 % over lesebakgrunnen, med `--color-text` på:
     lys   30 % #3d6b53 over #fbfaf7 → rgb(194,207,198) · #1b1a17 gir 10,9:1
     mørk  30 % #9dc4ac over #26241f → rgb(74,84,73)    · #f7f5f0 gir  7,3:1

   AKSENT OG IKKE GRÅTT, med grunn: markeringen er den ene flata på skjermen
   BRUKEREN lager. Den skal være husets farge. Og ikke `--color-accent-2` —
   den betyr «noe er unormalt», og å markere en setning er ikke det.

   GJENNOMSIKTIG, IKKE FAST: teksten under beholder sin egen farge, så
   markeringen virker på en dempet linje, en lenke og en overskrift uten tre
   regler. Kostnaden står under.

   R19 · DET SOM GJØR VERDIEN USANN: en aksentfylt flate. 30 % aksent blandet
   inn i aksent er aksent — **markeringen forsvinner der, uten å feile.**
   I dag er de flatene knapper, valgte segmenter og aktiv menyrad, og ingen av
   dem er lesetekst. Den dagen brødtekst legges på en aksentfylt flate, er det
   ikke markeringen som skal rettes. */
::selection { background: color-mix(in srgb, var(--color-accent) 30%, transparent); }

/* — rules — */
.hr {
  height: 1px; border: 0; margin: var(--space-4) 0;
  background: var(--color-divider);
}

/* — buttons —
   Kontrollfamilien sto på 14 — åtte regler, ett tall: .btn, .input, .radio,
   .check, .switch, .dialog-body, .nav a, .table. Dommen 24. august: en avrunding,
   ikke et valg mot skalaen — 14 finnes verken i skalaen eller i bygget (knappene
   målt til 16, Picos felter 1rem = 16). Rettet i steg 2, 25. august: kontrollene
   til 16 (--f3), tabellradene til 13 (--f2 — løpende tekst i rader er dens jobb).
   Før/etter står i «Steg 2 Kontrollfamilien». */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  cursor: pointer; text-decoration: none;
  font-family: var(--font-body); font-weight: 500;
  font-size: 16px; line-height: 1.2; color: var(--color-text); /* matches the .input's 16px —
     the pair sits side by side in sign-up rows */
  background: transparent; border: 1px solid transparent;
  padding: var(--space-2) calc(var(--space-3) * 1.2);
  border-radius: var(--radius-md);
}
.btn svg { display: block; }
.btn-primary { background: var(--color-accent); color: var(--color-bg); }
.btn-primary:hover { background: var(--color-accent-600); }
.btn-primary:active { background: var(--color-accent-700); }
/* Kantet bærer aksenten. Dommen i «Knappene og skalaen» (23. august, levert 24.):
   bygget har aksentkant og aksentblekk, og bygget har rett — en andre-rekke-knapp
   i nøytral kant leses som sperret. Nøytral kant og nøytrale hover-flater sto her
   til 24. august. */
.btn-secondary { border-color: var(--color-accent); color: var(--color-accent); }
.btn-secondary:hover { background: var(--color-accent-100); }
.btn-secondary:active { background: var(--color-accent-200); }
.btn-ghost { color: var(--color-accent); padding-inline: var(--space-1); }
.btn-ghost:hover { background: var(--color-accent-100); }
.btn-ghost:active { background: var(--color-accent-200); }
.btn-icon { width: 44px; height: 44px; padding: 0; }  /* 44 er minste trykkflate, jf. 15a */
.btn-block { width: 100%; margin-top: var(--space-2); justify-content: flex-start; text-align: left; }

/* — forms — */
.input {
  width: 100%; min-height: 36px; padding: 6px 10px; font: inherit;
  font-size: 16px; color: var(--color-text); caret-color: var(--color-accent);
  background: var(--color-surface);
  border: 1px solid var(--color-field-border); border-radius: var(--radius-md);
}
.input:hover { border-color: var(--color-text); }
.input:focus-visible { border-color: var(--color-accent); outline-offset: 0; }
textarea.input { min-height: 90px; resize: vertical; }
.radio { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; font-size: 16px; }
.radio input, .seg-opt input {
  position: absolute; opacity: 0; width: 0; height: 0; pointer-events: none;
}
.radio .dot {
  width: 16px; height: 16px; flex: none; border-radius: 50%;
  border: 1.5px solid var(--color-field-border);
}
.radio:hover .dot { border-color: var(--color-accent); }
.radio input:checked + .dot {
  border-color: var(--color-accent); background: var(--color-accent);
  box-shadow: inset 0 0 0 4px var(--color-bg);
}
.radio input:focus-visible + .dot { outline: 2px solid var(--color-accent); outline-offset: 2px; }
.seg {
  display: inline-flex; overflow: hidden;
  border: 1px solid var(--color-field-border); border-radius: var(--radius-md);
}
/* GULVET STÅR HER, IKKE I PUNKT 5. Design målte kontrollen til 34 px 22. august
   — 7 + 20 + 7 — og meldte den. Punkt 5 setter 44 px, men bare under 640 px, og
   en segmentkontroll er den ENE kontrollen i huset som nesten alltid står på bred
   skjerm: pakkevelgeren, bransjevelgeren, avtalepartvelgeren, draktvelgeren. Alle
   fire står over 640, så beholderspørringen traff dem aldri. **Trykkflaten er ikke
   en telefonregel** — punkt 8 i terskelen sier «i alle drakter», og det gjelder
   like fullt alle bredder. Høyden står derfor på klassen selv. */
.seg-opt {
  display: inline-flex; align-items: center; gap: 6px;
  min-height: 44px; padding: 7px 12px; font-size: 13px; cursor: pointer;
}
.seg-opt + .seg-opt { border-left: 1px solid var(--color-field-border); }
/* DET VALGTE ALTERNATIVET HAR INGEN DEMPET TEKST. Målt av design 22. august og
   hjem hit 23. august: prisen i den valgte pakkeknappen sto på
   `--color-text-muted` og målte 1,08 mot aksentflata i lys og 1,16 i mørk —
   tallet operatøren kom for var det ene som var usynlig. Arver navnets farge,
   som er målt til 4,92 og 9,05.

   Regelen er skrevet på barna og ikke på et navn, fordi andrelinja heter noe
   forskjellig i hver tegning. Inne i et valgt alternativ finnes ingen dempet
   farge — det er hele setningen. */
.seg-opt:has(input:checked) > * { color: inherit; }
.seg-opt:has(input:checked) { background: var(--color-accent); color: var(--color-bg); }
.seg-opt:not(:has(input:checked)):hover { background: var(--color-neutral-200); }
.seg-opt:has(input:focus-visible) { outline: 2px solid var(--color-accent); outline-offset: -2px; }

/* — cards — */
.card {
  display: flex; flex-direction: column; gap: var(--space-2);
  padding: var(--space-3); border-radius: var(--radius-md); background: var(--color-surface);
  border: 1px solid var(--color-divider);
}
.card-kicker { font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--color-accent); }
.card-title {
  font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: 18px; line-height: 1.25;
}
.card-body { margin: 0; font-size: 13px; color: var(--color-neutral-800); flex: 1; }
.card-meta {
  display: flex; align-items: center; gap: 6px; font-size: 11px;
  color: var(--color-text-muted);
}
.elev-sm { box-shadow: var(--shadow-sm); }
.elev-md { box-shadow: var(--shadow-md); }
.elev-lg { box-shadow: var(--shadow-lg); }

/* — tags — */
.tag {
  display: inline-flex; align-items: center; font-size: 11px;
  letter-spacing: 0.02em; padding: 3px 10px;
  border-radius: calc(var(--radius-md) * 0.75);
}
.tag-accent { background: var(--color-accent-100); color: var(--color-accent-800); }
.tag-accent-2 { background: var(--color-accent-2-100); color: var(--color-accent-2-800); }
.tag-neutral { background: var(--color-neutral-100); color: var(--color-neutral-800); }
.tag-outline { border: 1px solid var(--color-accent); color: var(--color-accent); }

/* — navigation — */
.nav {
  display: flex; align-items: center; gap: var(--space-4);
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--color-divider);
}
.nav-brand {
  font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: 18px; margin-right: auto;
}
.nav a { color: inherit; text-decoration: none; font-size: 16px; }
.nav a:hover, .nav a[aria-current='page'] { color: var(--color-accent); }

/* — tables — */
.table { width: 100%; border-collapse: collapse; font-size: 13px; } /* 13 = --f2, løpende
   tekst i rader. De sju andre i kontrollfamilien gikk til 16 — steg 2, 25. august. */
.table th {
  text-align: left; font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--color-text-muted);
  padding: var(--space-2); border-bottom: 1px solid var(--color-divider);
}
.table td {
  padding: var(--space-2);
  border-bottom: 1px solid var(--color-divider);
}
.table tbody tr:hover { background: var(--color-neutral-100); }

/* — dialog — */
.dialog-backdrop {
  position: fixed; inset: 0; display: grid; place-items: center;
  padding: var(--space-4);
  background: color-mix(in srgb, var(--color-neutral-900) 50%, transparent);
}
.dialog {
  width: min(440px, 100%); display: flex; flex-direction: column; gap: var(--space-3);
  padding: var(--space-4); border-radius: var(--radius-lg);
  background: var(--color-surface); box-shadow: var(--shadow-lg);
}
.dialog-title {
  font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: 20px;
}
.dialog-body { font-size: 16px; color: var(--color-neutral-800); }
.dialog-actions { display: flex; justify-content: flex-end; gap: var(--space-2); margin-top: var(--space-2); }

/* ══════════════════════════════════════════════════════════════════════════
   TILLEGG TIL ds.css — steg 1 i IMPLEMENTERINGSLISTE.md
   Tre feltyper som mangler, og .btn:disabled i målte verdier.

   Alle farger er tokens fra :root. Ingenting her er en ny farge, en ny
   avstand eller en ny radius — da ville tillegget ha vært en ny sannhet
   ved siden av den som finnes.

   Alle tall under er målt i begge drakter. Kontrastene står i kommentar
   der de er et krav, ikke der de bare er høye.
   ═══════════════════════════════════════════════════════════════════════ */


/* ── 1 · Nedtrekk ───────────────────────────────────────────────────────────
   Ingen egen flate: nedtrekket ER .input. Bare pilen og appearance kommer
   i tillegg, så det finnes én sannhet om hvordan et felt ser ut.

   Pilen tegnes i CSS av to kanter, ikke av en fil og ikke av nettleserens
   egen. Da arver den tekstfargen, virker i begge drakter, og henter
   ingenting fra en tredjepart (R7).

   Markup:
     <div class="field">
       <label>Bransje</label>
       <div class="select">
         <select class="input">…</select>
       </div>
     </div>

   Verdiene i listen utledes av kilden sin, de skrives ikke av (R2).
   ───────────────────────────────────────────────────────────────────────── */
.select { position: relative; display: block; }
.select select.input {
  appearance: none; -webkit-appearance: none;
  padding-right: 32px;
  cursor: pointer;
}
.select::after {
  content: ""; position: absolute; right: 13px; top: 50%;
  width: 7px; height: 7px; margin-top: -6px;
  pointer-events: none;
  border-right: 1.5px solid var(--color-text-muted);   /* 6,3:1 lys · 7,0:1 mørk */
  border-bottom: 1.5px solid var(--color-text-muted);
  transform: rotate(45deg);
}
.select:has(select:disabled)::after { border-color: var(--color-neutral-600); }
/* Noen nettlesere tegner listen som åpnes med systemets egne farger.
   Disse to linjene tvinger den inn i drakta. */
.select select.input option { background: var(--color-surface); color: var(--color-text); }


/* ── 2 · Avkryssingsboks ────────────────────────────────────────────────────
   Bygget som .radio: det ekte feltet ligger der, skjult for øyet, synlig
   for skjermleseren. Boksen er en <span> vi tegner selv.

   Markup:
     <label class="check">
       <input type="checkbox"><span class="box"></span>
       Vis siden i hovedmenyen
     </label>

   flex-start, ikke center: samtykketeksten er tre linjer på telefon, og
   boksen skal stå ved den første linjen — ikke midt i avsnittet.

   :indeterminate er tatt med fordi «arvet utvalg» har en overordnet rad
   som verken er alt eller ingenting. Den koster fire linjer nå.
   ───────────────────────────────────────────────────────────────────────── */
.check {
  display: inline-flex; align-items: flex-start; gap: 8px;
  cursor: pointer; font-size: 16px;
}
.check input {
  position: absolute; opacity: 0; width: 0; height: 0; pointer-events: none;
}
.check .box {
  position: relative; width: 16px; height: 16px; flex: none; margin-top: 3px;
  background: var(--color-surface);
  border: 1.5px solid var(--color-field-border);       /* 5,4:1 lys · 4,2:1 mørk */
  border-radius: 4px;
}
.check:hover .box { border-color: var(--color-accent); }
.check input:checked + .box,
.check input:indeterminate + .box {
  background: var(--color-accent); border-color: var(--color-accent);
}
.check input:checked + .box::after {                    /* haken */
  content: ""; position: absolute; left: 4px; top: 0.5px;
  width: 4px; height: 8px;
  border-right: 2px solid var(--color-bg);              /* 4,9:1 lys · 9,1:1 mørk */
  border-bottom: 2px solid var(--color-bg);
  transform: rotate(45deg);
}
.check input:indeterminate + .box::after {              /* streken */
  content: ""; position: absolute; left: 2.5px; top: 5.5px;
  width: 8px; height: 2px; background: var(--color-bg);
}
.check input:focus-visible + .box {
  outline: 2px solid var(--color-accent); outline-offset: 2px;
}
/* Sperret betyr «det pågår», ikke «du har ikke tilgang». Boksen beholder
   formen sin; det som endrer seg er at teksten blir dempet — en målt farge
   (6,3:1 lys · 7,0:1 mørk), ikke en uttoning. */
.check:has(input:disabled) { cursor: not-allowed; color: var(--color-text-muted); }
.check:has(input:disabled):hover .box { border-color: var(--color-field-border); }
.check:has(input:disabled):hover input:checked + .box { border-color: var(--color-accent); }


/* ── 3 · Av/på-bryter ───────────────────────────────────────────────────────
   Markup:
     <label class="switch">
       <input type="checkbox" role="switch"><span class="track"></span>
       Nyhetsbrev
     </label>

   role="switch" er det som gjør at skjermleseren sier «på» og «av» i
   stedet for «avkrysset». Uten den er dette en avkryssingsboks som ser
   ut som en bryter.

   .switch-end når bryteren skal stå ytterst til høyre i en rad — det er
   formen modulbryterne i eierdøren har.

   Knotten er --color-neutral-100 og av-sporet --color-neutral-600.
   neutral-600 er det ene trinnet som har samme verdi i begge drakter,
   og knotten følger flata. Derfor holder bryteren målet begge veier
   uten en eneste overstyring for mørk drakt:
     av   knott mot spor   3,5:1 lys · 4,2:1 mørk
     på   knott mot spor   5,7:1 lys · 8,1:1 mørk
     spor mot flata under  3,6:1 lys · 4,2:1 mørk
   ───────────────────────────────────────────────────────────────────────── */
.switch {
  display: inline-flex; align-items: center; gap: 10px;
  cursor: pointer; font-size: 16px;
}
.switch input {
  position: absolute; opacity: 0; width: 0; height: 0; pointer-events: none;
}
.switch .track {
  position: relative; width: 38px; height: 22px; flex: none;
  background-color: var(--color-neutral-600);
  border-radius: 11px;
  transition: background-color 120ms ease;
}
.switch .track::after {
  content: ""; position: absolute; top: 3px; left: 3px;
  width: 16px; height: 16px; border-radius: 50%;
  background: var(--color-neutral-100);
  transition: transform 120ms ease;
}
.switch:hover .track { background-color: var(--color-neutral-700); }
.switch input:checked + .track { background-color: var(--color-accent); }
.switch:hover input:checked + .track { background-color: var(--color-accent-600); }
.switch input:checked + .track::after { transform: translateX(16px); }
.switch input:focus-visible + .track {
  outline: 2px solid var(--color-accent); outline-offset: 2px;
}
.switch:has(input:disabled) { cursor: not-allowed; color: var(--color-text-muted); }
.switch:has(input:disabled):hover .track { background-color: var(--color-neutral-600); }
.switch:has(input:disabled):hover input:checked + .track { background-color: var(--color-accent); }
.switch-end { flex-direction: row-reverse; justify-content: space-between; width: 100%; }

/* Bryteren flytter seg. Den som har slått av bevegelse i systemet skal se
   at den er flyttet, ikke se den flytte seg. */
@media (prefers-reduced-motion: reduce) {
  .switch .track, .switch .track::after { transition: none; }
}
/* Longhand `background-color`, ikke kortformen `background`. Det endrer
   ingenting visuelt — det er en presisering, så transisjonen gjelder fargen
   og ikke hele bakgrunnsfamilien. Se merknaden nederst i fila om målingen
   som rapporterte gjennomsiktig; den skyldes ikke dette. */


/* ── 4 · Sperret, i målte verdier ───────────────────────────────────────────
   Erstatter  .btn:disabled { opacity: 0.45; cursor: not-allowed; }

   Den gamle linjen målte 1,9:1 på primærknappen i lys drakt og 2,9:1 i
   mørk. Grunnen er at gjennomsiktighet blander BÅDE flata og skriften
   mot det samme underlaget — de nærmer seg hverandre, og teksten
   forsvinner inn i knappen.

   Sperret betyr én ting hos oss: DET PÅGÅR. Det betyr aldri «du har ikke
   tilgang» — det sier vi med ord, ikke ved å gjøre en knapp blek.
   Derfor er den sperrede knappen fortsatt lett å lese:
     tekst mot flate   6,6:1 lys · 7,2:1 mørk
   ───────────────────────────────────────────────────────────────────────── */
.btn:disabled,
.btn[aria-disabled="true"] {
  cursor: not-allowed;
  background: var(--color-neutral-300);
  color: var(--color-neutral-800);
  border-color: var(--color-neutral-300);
}
.btn:disabled:hover,
.btn[aria-disabled="true"]:hover { background: var(--color-neutral-300); }

/* aria-disabled er tatt med fordi :disabled tar knappen ut av
   tabulatorrekkefølgen. Trykker hun Lagre og knappen sperres, mister hun
   fokus midt i skjemaet. aria-disabled beholder fokus og sier det samme. */

/* Feltet mangler den samme regelen. Samme tall, samme grunn.
     tekst mot flate   7,3:1 lys · 8,3:1 mørk */
.input:disabled {
  cursor: not-allowed;
  background: var(--color-neutral-200);
  color: var(--color-neutral-800);
  border-color: var(--color-neutral-400);
}
.input:disabled:hover { border-color: var(--color-neutral-400); }


/* ── 5 · Trykkflate på smal skjerm ──────────────────────────────────────────
   Besluttet 14. august 2026. Skrevet om 14. august etter et funn fra design.

   Tegningene sier «minst 44 × 44 px» (15a). ds.css sto på 36 px for felter
   og 35 px for knapper. Her rettes det ett sted, for alle feltypene på én
   gang — i stedet for i hver skjerm som oppdager det.

   FØRSTE FORSØK VAR `@media (max-width: 640px)`, OG DET VAR FEIL.
   Prototypens mobilvisning er ikke et smalt vindu — den er en 390 px bred
   spalte inne i et bredt vindu. En regel som spør etter VINDUSBREDDE slår
   derfor aldri til der. Feltene sto 36 px i mobilvisningen, og terskelen
   («den står i prototypen på telefon») kunne ikke kontrolleres i det hele
   tatt.

   Regelen spør nå etter BREDDEN PÅ PLASSEN KONTROLLEN HAR, ikke etter
   bredden på vinduet. Det er også det riktigere spørsmålet: en knapp bryr
   seg om hvor mye plass den har, ikke om hvor stor skjermen er.

   Målt 14. august, i vindu på 1400 px og 500 px:
     · 390 px skall i et 1400 px vindu  → 44 px   (som skal)
     · fullbredde skall i samme vindu   → 36 px   (som skal)
     · innloggingssiden, som ikke har noe skall → følger vinduet
     · `position: fixed` påvirkes ikke — dialogens bakteppe dekker fortsatt
       hele vinduet, ikke bare skallet. Dette ble målt fordi det er den ene
       kjente bivirkningen av å gjøre noe til en beholder. `contain: layout`
       fanger et fast plassert element; `container-type: inline-size` gjør
       det ikke.

   To ting må stå riktig for at dette skal virke:
     · Elementet som måles må ha en bredde som ikke kommer fra innholdet.
       `width: 390px` eller full bredde er greit; «så bredt som innholdet»
       er det ikke.
     · Har en skjerm ikke noe `.shell` — innloggingssiden er den ene —
       måles `body`, som er like bred som vinduet. Da oppfører regelen seg
       nøyaktig som den gamle. Ingen skjerm faller utenfor.

   FUNNET 15. AUGUST, OG DET ER EN FELLE MED TENNER NÅ: et skall som får bredden
   sin AV INNHOLDET måler 0 px, ikke «så bredt som innholdet». `container-type:
   inline-size` inneholder inline-aksen, så elementet bidrar ikke lenger til sin
   egen spaltebredde — i en `display:grid; place-items:start center` uten definitt
   spalte blir det en sirkel som ender på null. Og **0 px er mindre enn 640 px på
   enhver skjerm**, så telefonformen slår inn på bred skjerm også.

   Punktet advarte alt mot dette. Forskjellen er at det til nå bare hang
   `min-height` på beholderen, og en 44 px trykkflate på bred skjerm ser riktig
   ut. Fra punkt 13 STYRER beholderspørringen layouten, og da er den samme feilen
   en ødelagt skjerm. Prøven er én linje og bør stå i hver fil:

       document.querySelector(".shell").getBoundingClientRect().width > 0

   Og den tåler at prototypen senere flyttes inn i en ekte 390 px-ramme:
   da er skallet fortsatt det som måles, og svaret blir det samme.
   ───────────────────────────────────────────────────────────────────────── */
body, .shell, .fon { container-type: inline-size; }
/*                 ↑
   `.fon` er telefonrammen i tegningene. Den finnes IKKE i produktet, og står
   her bare fordi den ellers måtte gjentas i elleve tegningsfiler. Den er med
   i et navngitt selskap og ikke gjemt: alt som er «vinduet» for det som står
   inni, måler seg selv. `.fon` er en av dem, men bare på tegnebordet.
   Den slettes når ds.css flyttes inn i repoet i steg 2. */

@container (max-width: 640px) {
  /* .seg-opt sto her og er ute: høyden står på klassen selv nå, for alle bredder.
     En regel som gjentar noe som alt er sant er ikke gratis — den sier at det
     bare gjelder her. */
  .btn, .input { min-height: 44px; }
  .check, .radio, .switch { min-height: 44px; padding-block: 11px; }
  .tap { min-height: 44px; }        /* se punkt 10 */
}


/* ── 6 · Feltetiketten skjermes ─────────────────────────────────────────────
   Funnet av design 14. august, og det er et ekte funn.

   `.field > label` i ds.css traff ALLE etiketter inne i et felt — også en
   avkryssingsboks eller en bryter, som selv er en `<label>`. Da ble boksen
   tegnet som en liten dempet overskrift: 12 px, blokk, med luft under.

   DENNE LINJEN I ds.css SKAL SLETTES:
       .field > label { display: block; font-size: 12px; margin-bottom: 5px;
                        color: var(--color-text-muted); }
   og erstattes av den under.

   Hvorfor `:not([class])` og ikke en oppramsing av `.check`, `.switch` og
   `.radio`: en oppramsing er en liste som må vedlikeholdes, og den er
   allerede utdatert den dagen en fjerde kontroll kommer. R2 sier at lister
   av verdier utledes, aldri skrives av.

   Regelen utledes av noe som allerede er sant i alle 32 tegningene, talt
   14. august: 92 `<label>`, 33 av dem med klasse. Alle 33 er kontroller —
   27 `.seg-opt` og 6 `.radio`. Ingen feltetikett har klasse. Fire har et
   `style`-attributt, og de treffes fortsatt, fordi `style` ikke er `class`.

       en etikett uten klasse er en overskrift over et felt
       en etikett med klasse er selve kontrollen

   `legend` og `.caption` er tatt med fordi en GRUPPE av avkryssingsbokser
   også trenger en overskrift, og den kan ikke være en `<label>` — en label
   peker på ett felt. Uten dette blir overskriften en `<span>` som er malt
   til å ligne, og da har vi to sannheter om hvordan en feltetikett ser ut.
   ───────────────────────────────────────────────────────────────────────── */
.field > label:not([class]),
.field > legend,
.field > .caption {
  display: block;
  font-size: 12px;
  margin-bottom: 5px;
  color: var(--color-text-muted);
}
/* FELTET I VANLIG FLYT. Hjem hit 23. august fra `A Dørene og kontoene` og
   `Innlogging og sidevalg`, som begge skrev `.field { margin-top: 14px }` i sitt
   eget stilark. Verdien er deres og er ikke endret.

   Den har et eget navn, og det er en beslutning: et felt i en flex-kolonne med
   `gap` får avstanden av kolonnen, og legges margen på `.field` selv, står
   avstanden to ganger i hver slik skjerm. Innloggingsskjemaene står i vanlig
   flyt og har ingen kolonne å arve fra — de tar `.field-flyt`. Alt annet lar
   `gap` gjøre jobben. */
.field-flyt { margin-top: 14px; }


/* ── Merknad om en måling, ikke en feil ─────────────────────────────────────
   Design meldte at `.switch .track` rapporterer gjennomsiktig til første
   overgang har gått, og pekte på `transition`. Jeg har prøvd de fire
   forklaringene som er mulige, alle i Chromium 141:

     kortform med var() og transisjon   → riktig farge
     kortform med var() uten transisjon → riktig farge
     longhand med var()                 → riktig farge
     klonet fra en mal og målt straks   → riktig farge
     inne i `display: none`             → riktig farge
     et element som ikke står i siden   → TOM

   Bare det siste gir tom verdi. Transisjonen har ingenting med det å gjøre.
   Målingen leser et element som ikke er satt inn i dokumentet ennå — eller
   som står i et dokument uten stilarket. Stilarket er i orden; prøven
   trenger å måle etter innsetting.

   Det er verdt å merke seg som en husregel: EN MÅLING SOM GIR TOM VERDI HAR
   IKKE MÅLT NOE. Den skal si fra, ikke rapportere «gjennomsiktig».
   ───────────────────────────────────────────────────────────────────────── */

/* ── 7 · Kodefeltet ─────────────────────────────────────────────────────────
   Funnet av design 14. august: feltet finnes i tre tegninger — A1, A2 og I5
   — og i ingen av dem i ds.css. Det er nøyaktig den doble sannheten steg 1
   skal hindre, og den var på vei til å skje for tredje gang.

   TEGNINGENE VISER SEKS RUTER. DET BLIR ETT FELT. Fire grunner, i den
   rekkefølgen de veier:

   1. Telefonen. `autocomplete="one-time-code"` gjør at koden fra SMS-en
      tilbys rett over tastaturet, som ett trykk. Over seks felter fyller
      de fleste nettlesere bare den første ruta. Onboardingen skjer på
      telefon. Da er dette ikke en detalj, det er hele forskjellen på ett
      trykk og seks.
   2. ds.css sier om seg selv: «Plain CSS on plain HTML: no JavaScript, no
      build step.» Seks ruter KAN ikke virke uten JavaScript — innliming,
      slettetast og hvor markøren hopper må alle skrives. Det ville vært den
      første delen i grunnmuren som trenger kode for å fungere.
   3. Skjermleseren hører ett felt med ett navn, ikke seks navnløse.
   4. Innliming og sletting virker uten at noen har skrevet noe.

   Seks ruter har én ekte fordel: de viser hvor mange sifre som ventes uten
   at det står noe sted. Den fordelen tas her av `maxlength` og sifferavstanden.

   Så: seks ruter er et BILDE av en kode. Ett felt ER en kode.

   Markup:
     <input class="input input-code" type="text" inputmode="numeric"
            autocomplete="one-time-code" maxlength="6" placeholder="000000">

   Ikke `type="number"`. Den gir opp/ned-piler, og den spiser ledende null.

   `text-indent` er ikke pynt. Sifferavstanden legger også luft ETTER siste
   siffer, og da faller sentreringen mot venstre. Målt i malte piksler, ikke
   i det nettleseren rapporterer:
     uten text-indent   blekket står 5 px for langt til venstre
     med text-indent    1 px unna midten
   (Det nettleseren rapporterte, sa det motsatte. Pikslene avgjorde.)
   ───────────────────────────────────────────────────────────────────────── */
/* Den lyse paletten henger på BEGGE: roten, og et undertre som sier at det er lyst.
   Uten det andre leddet arver en lys drakt inne i siden de mørke verdiene den dagen
   maskinen står i mørk modus — `:not([data-drakt="lys"])` beskytter elementet regelen
   treffer, aldri etterkommerne. Tegningene våre viser lys og mørk side om side, så
   dette er ikke et kanttilfelle her; det er hovedtilfellet. */
:root, [data-drakt="lys"] {
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
               "Liberation Mono", monospace;
}
.input-code {
  font-family: var(--font-mono);
  font-size: 22px;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.38em;
  text-indent: 0.38em;      /* motvekt mot luften etter siste siffer */
  text-align: center;
  min-height: 52px;
  padding-inline: 8px;
  width: 100%;
  max-width: 15ch;
}
/* Reservekoden er lengre og har bokstaver og bindestrek. Samme felt, uten
   taket på bredden. */
.input-code-long { max-width: 24ch; }


/* ── 8 · Valgkort ───────────────────────────────────────────────────────────
   Funnet i A2 (maskinvalget) og A4 (rollevalget): et valg der alternativet
   er to setninger, ikke tre ord. Rammen sto inline i skjermen begge steder.

   `.choice` legges PÅ `.radio` eller `.check` — den erstatter dem ikke.
   Kontrollen, tastaturet og skjermleseren er fortsatt den som står i
   punkt 2 og i ds.css fra før. Kortet er bare rammen rundt.

   Markup:
     <label class="radio choice">
       <input type="radio" name="rolle"><span class="dot"></span>
       <span class="choice-text">
         <span class="choice-title">Daglig leder</span>
         <span class="choice-sub">Ser alt, kan invitere andre, og er den
         eneste som kan si opp abonnementet.</span>
       </span>
     </label>

   To ting er målt her, og den ene rettet min egen antakelse:

   KANTEN, IKKE FLATA. Jeg skrev først at valgt kort skulle kjennes på både
   aksentkant og lys aksentflate, «for én av dem alene er ikke nok». Så målte
   jeg: den lyse aksentflata mot den vanlige flata er 1,07:1 i lys drakt.
   Det er ingen forskjell — det er en påstand. Flata blir stående fordi den
   er en nyanse som ikke koster noe, men den er ikke et signal, og den skal
   ikke omtales som ett. DE TO EKTE SIGNALENE ER PRIKKEN, som er selve
   kontrollen, OG AKSENTKANTEN, som måler 4,9:1 lys og 9,1:1 mørk mot flata
   rundt.

   KANTEN PÅ DET UVALGTE ER `--color-field-border`, IKKE `--color-divider`.
   Skillelinjefargen måler 1,15:1 mot siden — kortet ville hatt en kant man
   ikke kan se. Et kort man kan trykke på er en kontroll, og en kontroll må
   ha synlig kant. Det er den samme regelen `.input` alt følger, og derfor
   den samme fargen.
   ───────────────────────────────────────────────────────────────────────── */
.choice {
  display: flex; align-items: flex-start; gap: 10px; width: 100%;
  padding: 12px 14px;
  background: var(--color-surface);
  border: 1px solid var(--color-field-border);   /* 4,5:1 mot siden */
  border-radius: var(--radius-md);
}
.choice + .choice { margin-top: var(--space-2); }
.choice:hover { border-color: var(--color-text); }   /* som .input:hover */
.choice:has(input:checked) {
  border-color: var(--color-accent);
  background: var(--color-accent-100);
}
.choice:has(input:focus-visible) {
  outline: 2px solid var(--color-accent); outline-offset: 2px;
}
.choice-text { display: block; }
.choice-title { display: block; font-weight: 500; }
.choice-sub {
  display: block; margin-top: 2px;
  font-size: 12.5px; color: var(--color-text-muted);
}
/* Prikken står ved første linje, ikke midt i avsnittet — samme grunn som
   avkryssingsboksens flex-start i punkt 2. */
.choice .dot, .choice .box { margin-top: 3px; }


/* ── 9 · To svar som veier likt ─────────────────────────────────────────────
   Avgjort 14. august 2026, etter et funn fra design i A5.

   REGELEN: DER KUNDEN GIR ELLER NEKTER NOE, ER INGEN AV SVARENE PRIMÆR.

   Primærknappen betyr «dette anbefaler vi». På et samtykke skal vi ikke
   anbefale. Står «Ja» som fylt knapp og «Nei» som kantet, har skjermen
   allerede svart før kunden gjorde det — og på bred skjerm, der de to ikke
   lenger er like brede, leses det tydelig.

   Gjelder: innsyn, samtykke, sletting, oppsigelse, avmelding. Alt der
   kunden gir fra seg noe eller tar noe tilbake.

   Gjelder IKKE «vil du lagre», «vil du publisere». Der finnes det et
   anbefalt valg, og da skal knappen si det.

   Prøven er enkel og bør skrives: PÅ EN SAMTYKKESKJERM FINNES DET INGEN
   `.btn-primary`. Den kan ikke være grønn fordi den ikke ser — den teller.

   Markup:
     <div class="btn-pair">
       <button class="btn btn-secondary">Ja, gi innsyn</button>
       <button class="btn btn-secondary">Nei</button>
     </div>
   ───────────────────────────────────────────────────────────────────────── */
.btn-pair { display: flex; gap: var(--space-2); }
.btn-pair > .btn { flex: 1 1 0; }
@container (max-width: 400px) {
  /* På telefon står de under hverandre — men fortsatt like brede og
     fortsatt uten en primær. Rekkefølgen endres ikke: den som står øverst
     på telefon er den samme som står til venstre på bred skjerm. */
  .btn-pair { flex-direction: column; }
}


/* ── 10 · Alt annet som kan trykkes ─────────────────────────────────────────
   Funnet av design 14. august: seks lenker i område A bar `min-height: 44px`
   skrevet inn i skjermen, «fordi det ikke finnes noe å arve».

   Design kalte det en sjuende feltype. Det er det ikke. Det er at punkt 5
   RAMSER OPP KLASSER i stedet for å stille et spørsmål — og en oppramsing er
   den lista R2 advarer mot. Den holdt for seks tilfeller og røk på det sjuende.

   `.tap` er svaret på spørsmålet punkt 5 egentlig stiller: KAN DETTE TRYKKES?
   Er svaret ja, og tingen ikke alt er en av de seks, får den `.tap`.
   **Aldri et tall skrevet inn i skjermen.**

   Det andre tilfellet finnes allerede i tegningene: «Hele raden er trykkflate,
   høyde 44 px.» En tabellrad man kan trykke på er ikke en lenke og ikke en
   knapp — men den er en trykkflate.

   `.tap` sier ingenting om hvordan tingen ser ut. En lenke ser ut som en
   lenke, en rad som en rad. Den sier bare at fingeren skal nå den.

   Markup:
     <a href="/glemt-passord" class="tap">Glemt passord</a>
     <tr class="tap"> … </tr>
   ───────────────────────────────────────────────────────────────────────── */
.tap { display: flex; align-items: center; }

/* OG FLEX ER FEIL SVAR FOR TRE AV FORMENE PUNKTET SELV RAMSER OPP.
   Meldt av Code 21. august, målt: `display:flex` på en `<tr>` river tabellen
   fra hverandre på bred skjerm, og på et kort legger den tittelen og
   setningen side om side — header x=296, avsnitt x=396, samme linje.

   Punktet sa allerede at `.tap` ikke bestemmer hvordan noe SER UT, bare at
   fingeren skal nå det — og satte så en layoutverdi på alt det traff. Linjen
   under er den setningen gjort sann: en rad er en rad, et kort er et kort, en
   listepost er en listepost. Bare det som ikke har en form fra før, får flex.

   `:where()` og ikke en vanlig selektor, fordi den ikke skal låne vekt fra
   punktet den retter — flaten skal kunne overstyre begge. */
:where(tr, article, li).tap { display: revert; }

/* Kortleddet — avgjort 18. august, meldt to ganger av Morten i gjennomgang:
   kort med én åpenbar handling kunne bare trykkes på tittelteksten.

   ETT KORT MED ÉN HANDLING ER ÉN TRYKKFLATE, OG DEN ER HELE KORTET.
   Tittelen er ikke en egen lenke inni — to flater oppå hverandre er to
   svar på samme trykk. Gjelder ALLE kortlister: punkt 13-kortene på
   telefon, Innstillinger-kortene (B13), Hjem-flisene (B4) og kundekortene
   i eierdørens liste. Avgjort her, én gang — ikke skjerm for skjerm.

   Tre krav følger med, og de bor her og ikke i skjermene:
   1. Fokus ligger på kortet. Hele kortet bærer fokusringen (regelen
      under), aldri bare tittelen.
   2. Et trykk som avslutter en tekstmarkering er ikke et trykk. Kortet
      navigerer bare når markeringen er tom (getSelection().isCollapsed) —
      teksten i et kort skal kunne markeres og kopieres uten at skjermen
      bytter.

      KRAVET GJELDER RADEN OG KORTET LIKT, og det er svaret på Codes
      spørsmål 21. august: kravet var formulert om kortet fordi kortet var
      det som ble tegnet, ikke fordi raden er unntatt. Formen er den samme
      — hele flaten svarer, og teksten i den skal kunne kopieres — og
      «tabellrad» står i punktets egen markup-eksempel to skjermer opp.

      MERK HVA MÅLINGEN VISTE, for det er to krav og ikke ett: draget tok
      HELE tabellen i stedet for den ene radens tekst, og etterpå åpnet
      raden seg ikke. Det andre er vakten; det første er at markeringen
      ikke er stengt inne i raden. En vakt som ser en levende markering
      spiser neste trykk uansett hvor markeringen begynte — så vakten må
      spørre om SIN EGEN flate. Se merknaden under fokusringen.
   3. Har kortet MER enn én handling, eier «åpne» flaten, og hver
      tilleggshandling er sin egen knapp på minst 44 px oppå flaten —
      aldri inni lenken, og et trykk på den utløser bare den. Har kortet
      ingen åpne-handling, er flaten død og handlingene er knapper. */
.tap:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }

/* OG HER ER GRENSEN FOR HVA GRUNNMUREN KAN GJØRE MED DEN.

   `user-select: contain` er det spesifikasjonen har for «markeringen
   begynner og slutter i denne flaten», og den er ikke å stole på i en
   tabell i dag. Så grunnmuren skriver ingen regel her, og kravet blir
   stående i punktet over som et krav på VAKTEN og ikke på stilarket:

     vakten spør om markeringen ligger inne i den flaten som ble trykket
     — ikke om det finnes en markering på siden.

   Forskjellen er hele funnet: et drag som strakk seg over hele tabellen
   ga en levende markering ved neste trykk i EN HVILKEN SOM HELST rad, og
   da ble trykket spist i alle elleve. Spør vakten om flaten sin, virker
   den uansett hvor langt markeringen rakk. */


/* ── 11 · Tilstandsprikken ──────────────────────────────────────────────────
   Funnet 14. august ved å søke i alle elleve tegningsfilene på én gang.

   NI FILER definerer sin egen `.dot` — en liten fylt sirkel som viser en
   tilstand. `ds.css` bruker allerede `.dot` til noe annet: prikken inne i en
   radioknapp, 16 × 16 med kant.

   Det går bra i dag, fordi `.radio .dot` vinner over en naken `.dot`. Men det
   er ETT ORD MED TO BETYDNINGER, og det er nøyaktig formen på feilen som
   nettopp kostet oss et døgn med `label`. Den venter bare på at noen skriver
   en tilstandsprikk inne i et valg.

   Prikken har alt begynt å drive: sju piksler i fire filer, åtte i fem.

   Fargene er husregelen, ikke en smakssak: **grønt betyr i orden, leire betyr
   at noen må gjøre noe. Rødt finnes ikke.** Står prikken uten en av de to, er
   den nøytral — og det er også et svar.

   RETTET 14. august, funnet av design. Den nøytrale prikken sto først på
   `--color-neutral-500`. Den var den ene av tre farger i dette punktet som
   ikke var målt — de to andre var det. Målt nå, mot flata den står på:

     neutral-500   2,46:1 lys · 2,77:1 mørk     ← under kravet i BEGGE
     neutral-600   3,55:1 lys · 4,18:1 mørk     ← holder

   En prikk som betyr noe er en kontroll, ikke pynt, og kravet er 3:1.
   `neutral-600` er dessuten det ene trinnet med samme verdi i begge drakter
   — samme grunn som av-sporet i punkt 3 bruker det.

   **Det var ikke prikkebyttet som skapte feilen. Byttet gjorde den synlig.**
   Fargen sto inline i ni filer og var aldri målt mot noen flate.

   Markup:
     <span class="state-dot state-dot-ok"></span>
   ───────────────────────────────────────────────────────────────────────── */
.state-dot {
  width: 8px; height: 8px; flex: none;
  border-radius: 50%;
  /* neutral-700, ikke -600: -600 er målt mot KORTET (3,55) og faller mot
     SIDENS flate (2,98). -700 holder begge: 4,50 og 5,37 lys · 6,78 og 6,04
     mørk. Se husregelen nederst i fila. */
  background: var(--color-neutral-700);
}
.state-dot-ok   { background: var(--color-accent); }
.state-dot-vent { background: var(--color-accent-2); }
/* PRIKKEN STÅR VED FØRSTE LINJE. Hjem hit 23. august: fire tegningsfiler skrev
   `margin-top: 5px` hver for seg, og fire som er enige er en husregel som ikke
   kom hjem. Verdien er ikke ny og den er ikke smak: prikken er 8 px, teksten
   ved siden av 12,5 px i 1,45 gir en linjeboks på 18,1 px, og (18,1 − 8) / 2 er
   5,05. Samme regel og samme grunn som `.choice .dot` i punkt 8, der linja er
   større og tallet derfor 3. */
.state-dot { margin-top: 5px; }
/* Raden som alt sentrerer selv sier det samme to ganger, og der skrives margen
   ned på stedet. Et eget navn for det ville vært en erklæring uten bruker. */


/* ── 12 · Stegprikken ───────────────────────────────────────────────────────
   Funnet av design 14. august, som en TREDJE betydning av en liten sirkel.
   Design ga den et lokalt navn og meldte den opp i stedet for å tvinge den
   inn i punkt 11. Det var riktig: `.state-dot-ok` ville sagt «i orden» om et
   steg som bare er passert.

   Fire betydninger av en liten sirkel, nå med hvert sitt navn:
     `.radio .dot`   prikken inne i et valg
     `.state-dot`    grønt i orden · leire noen må gjøre noe
     `.step-dot`     hvor langt hun er kommet
     romfargen       hvilket rom noe hører til — se merknaden nederst

   Brukes i onboardingen (seks steg) og i «Opprett ny kunde» (fire steg).

   OG DEN SKAL ALDRI STÅ ALENE. En rad med prikker sier ingenting til den som
   ikke ser dem. Ved siden av skal det stå «Steg 3 av 6» i ord — det er den
   eneste formen som virker for alle, og den virker også for den som ser.

   Markup:
     <span class="step-dot step-dot-passert"></span>
     <span class="step-dot step-dot-naa"></span>
     <span class="step-dot"></span>
     <span class="text-muted">Steg 3 av 6</span>
   ───────────────────────────────────────────────────────────────────────── */
.step-dot {
  width: 8px; height: 8px; flex: none;
  border-radius: 50%;
  background: var(--color-neutral-400);
}
.step-dot-passert { background: var(--color-neutral-600); }
.step-dot-naa {
  background: var(--color-accent);
  box-shadow: 0 0 0 3px var(--color-accent-200);
}


/* ── 13 · Tabellen på telefon: raden blir et kort ───────────────────────────
   Avgjort 15. august 2026. `0.7` er tegnet og sier «raden som kort på telefon»;
   formen fantes ikke i ds.css og ikke i tillegget. Ni tabeller i kundepanelet
   skyves sideveis på 390 px i dag, og hver eneste liste i D, I og H er en
   tabell. Rettes det underveis, blir det ni håndrettinger og en tiende som
   glemmes.

   ÉN MARKUP. Det er samme `<table class="table">` på begge bredder. Det finnes
   ingen kortliste ved siden av tabellen — to blokker som viser samme liste er
   to sannheter om den, og de går fra hverandre første gang noen legger til en
   kolonne i den ene.

   KOLONNENAVNET UTLEDES. CSS kan ikke lese teksten i `<th>` og flytte den ned
   i cellen; noe må bære navnet ned. Derfor bærer cellen `data-kol`, og kravet
   er hvor den verdien KOMMER FRA:

       {% for k in kolonner %}<th>{{ k.navn }}</th>{% endfor %}
       …
       {% for k in kolonner %}<td data-kol="{{ k.merkelapp }}">{{ … }}</td>{% endfor %}

   Samme løkke, samme liste. Skrives `data-kol` av for hånd, har vi to lister
   som må holdes i takt, og det er R2. **Prøven er at et kolonnenavn som endres
   ett sted endrer seg begge steder** — den kan skrives, og den bør det.

   `merkelapp` er kolonnens eget svar på om navnet trenger å bli med ned:
   «Avtalepart» → «Voso» sier seg selv, og kolonnen setter tom merkelapp.
   Det er ett valg per kolonne, tatt ett sted — ikke et valg per celle.

   ÉN CELLE ER I SETNINGEN BARE HVIS DEN HAR NOE Å SI.
   *(Skrevet 16. august. Erstatter tre rettelser, og det er derfor den står her
   og ikke som en fjerde.)*

   Punktet var skrevet som et KLASSIFISERINGSPROBLEM: del cellene i slag, og
   bestem hva hvert slag gjør. Første utgave hadde to slag — ledd og merke.
   Så møtte det tre tabeller, og tok feil på alle tre:

     I1c  et ledd uten merkelapp falt ut av setningen       → tredje slag
     I6c  handlingskolonnen sto inline midt i setningen     → fjerde slag
     G1c  en valgfri kolonne uten verdi ga «· Tid ·»        → femte slag

   Hver rettelse var tre linjer og så ut som et enkelttilfelle. Det er de ikke.
   **Et punkt som deler verden i slag, møter et nytt slag hver gang det brukes
   på noe det ikke er prøvd på** — og da er ikke rettelsen å legge til slaget.

   Sagt én gang er alle tre det samme: *har cellen noe å si?* Har den det, er
   den i setningen. Har den det ikke, er den ikke der — verken som en ensom «·»,
   som en etikett uten verdi eller som en ordløs sammenklistring. Det finnes
   ikke lenger slag, så et sjette kan ikke dukke opp.

   OG SPØRSMÅLET KAN IKKE STILLES I CSS. Det ble prøvd før dette ble skrevet,
   i nettleseren, 16. august:

       <td data-kol="Tid"></td>       :empty  ja    → kunne skjules
       <td data-kol="Tid"> </td>      :empty  NEI   → sto som før
       <td data-kol="Tid">\n  </td>   :empty  NEI   → sto som før

   `:empty` leser KILDETEGNENE, ikke innholdet: ett mellomrom fra en mal som
   bryter linjene sine annerledes, og regelen slår ikke til. Det er nøyaktig
   feilformen funn 8 hadde — en regel som avhenger av hvordan malen er brutt
   opp, er ikke en regel — og den skal ikke skrives inn igjen i ny drakt.

   DERFOR SVARER KILDEN, OG DEN SVARER MED `data-kol`.
   Attributtet fantes fra før, og bar to opplysninger på en gang: *er dette et
   ledd* og *hva heter kolonnen*. Nå bærer det én:

       data-kol finnes      cellen er i setningen — den har noe å si
       data-kol mangler     cellen er ikke i setningen

   Verdien er fortsatt merkelappen, og tom verdi betyr fortsatt «navnet trengs
   ikke med ned» — `attr()` gir tom streng, og setningen leser like riktig.
   Ett attributt, én betydning. Det er hele rettelsen.

   MALEN SKRIVER DET AV VERDIEN, IKKE AV KOLONNEN:

       {% for k in kolonner %}<th>{{ k.navn }}</th>{% endfor %}
       …
       {% for k in kolonner %}<td {% if verdi %}data-kol="{{ k.merkelapp }}"{% endif %}>…</td>{% endfor %}

   Samme løkke, samme liste, ett vilkår. Kolonnen bestemmer fortsatt om navnet
   skal med ned (`merkelapp`, ett valg per kolonne); VERDIEN bestemmer om cellen
   er med i det hele tatt. Handlingskolonnen har verken merkelapp eller verdi å
   melde — den skriver aldri attributtet, og trenger ingen egen regel lenger.

   **Prøven er at et kolonnenavn som endres ett sted endrer seg begge steder**,
   og nå også: *en tom verdi gir ingen tekst noe sted.*

   UTGANGSPUNKTET ER SNUDD, OG DET ER DET SOM GJØR REGELEN KORT.
   Før var alt `display: inline` — altså i setningen — og hvert unntak måtte
   tegnes ut. Nå er utgangspunktet EGEN LINJE, og bare det som er meldt inn i
   setningen er inline. Følgene faller ut av seg selv:

     · navnet              egen linje, som før
     · et ledd             inline, med «·» og merkelapp
     · handlingen          egen linje under setningen — ingen regel, bare fravær
     · en tom celle        en linje uten noe på seg, altså ingen linje
     · en umigrert tabell  en stabel, ikke en klistret setning

   Den siste er verdt å merke seg. `Kundepanelet`, `Eierdør` og `Innlogging` har
   tabeller som ennå ikke skriver `data-kol`. Før ble de til én ordløs remse;
   nå blir de en lesbar stabel. **Feiltilstanden til en regel hører med til
   regelen**, og en stabel er det riktige svaret på «ingen har fortalt meg hva
   som er en setning her».

   OG «EGEN LINJE» ER EN FLYT, IKKE EN BLOKK. Det er det ene stedet regelen
   ikke kunne skrives naivt, og det ble målt fram:

       display: block   tom celle midt i setningen BRYTER linjen
                        «fra 950» og «· 3 sider» havner på hver sin       ✗
                        rad, og kortet vokser 26 px
       float: left      en flyt uten innhold har ingen høyde og ingen
       clear: left      linje. Setningen står hel, kortet vokser 0 px     ✓
       width: 100%

   Målt 16. august, i tre rader: med tom celle, med verdi, og med en celle som
   inneholder ETT MELLOMROM — den siste er prøven `:empty` strøk på, og flyten
   består den: 73 px, samme som en rad uten kolonnen i det hele tatt.

   En flyt på full bredde kan ikke stå ved siden av noe, så den legger seg
   under linjen når den har innhold. Har den ingenting, finnes den ikke. Det er
   kriteriet sagt i layout i stedet for i en selektor, og det er derfor det
   ikke trengs noen test på innhold: **en linje uten noe på seg er ingen linje.**
   Raden er `display: flow-root` for å romme flytene sine.

   FORMEN KOMMER FRA 0.7c, og den er ikke en etikettliste:
     · første celle er radens navn, øverst til venstre, uten merkelapp
       (et navn trenger ingen etikett, og skriver derfor ikke `data-kol`)
     · cellen som bærer et `.tag` eller en `.state-dot` går til høyre på
       samme linje — merket sier selv hva det er, og skriver ikke `data-kol`
     · resten faller ned som ÉN setning, skilt med «·»
   Ingen vannrett rulling, aldri en sammenpresset tabell.

   Og det som er verdt å vite: på telefon er raden ikke lenger en tabellrad for
   skjermleseren heller — `display` tar bort tabellrollen. Det er ikke et tap
   som skjules her, det er den samme setningen tegningen alt sier: **kolonnehodet
   forsvinner, for det er ikke en kolonne lenger.** Derfor MÅ merkelappen stå i
   innholdet, ikke bare i hodet. Hodet skjules for øyet og for opplesningen
   samtidig, så ingen får lest opp en overskriftsrad som ikke finnes.
   ───────────────────────────────────────────────────────────────────────── */
@container (max-width: 640px) {
  .table, .table tbody { display: block; }
  .table thead { display: none; }
  .table tbody > tr + tr { margin-top: var(--space-2); }
  .table tr {
    display: flow-root;                 /* rommer cellene som flyter */
    position: relative;
    padding: 13px;
    background: var(--color-surface);
    border: 1px solid var(--color-divider);
    border-radius: var(--radius-md);
  }
  .table tbody tr:hover { background: var(--color-surface); }

  /* UTENFOR SETNINGEN = EGEN LINJE. En flyt på full bredde kan ikke stå ved
     siden av noe, så den legger seg under. Har den ingenting i seg, har den
     ingen høyde og ingen linje — og det gjelder også når malen har lagt et
     mellomrom inni cellen. Det er hele grunnen til at det er en flyt og ikke
     en blokk: en tom blokk BRYTER setningen i to. */
  .table td {
    float: left; clear: left; width: 100%;
    padding: 0; border: 0;
    font-size: 12.5px; line-height: 1.6;
    color: var(--color-neutral-800);              /* 7,3:1 lys · 8,3:1 mørk */
  }
  .table td:first-child {
    font-size: 14.5px; font-weight: 600;
    color: var(--color-text);
  }

  /* SETNINGEN. `inline`, ikke flex-barn eller blokk — det er hele grunnen til at
     leddene blir ÉN setning: de må dele samme inline-kontekst, ellers havner
     «·» først på hver sin linje. */
  .table td[data-kol] { float: none; width: auto; display: inline; }
  .table td[data-kol]::before { content: attr(data-kol) " "; }

  /* Skilletegnet står som ` · ` med mellomrom på BEGGE sider, og det leser ikke
     kilden: ledd nummer to og utover er «et ledd som har et ledd foran seg».
     Den mer spesifikke regelen vinner over den over, og det er tilsiktet. */
  .table td[data-kol] ~ td[data-kol]::before { content: " · " attr(data-kol) " "; }

  /* Merket står øverst til høyre, ute av setningsflyten. Navnet holder av
     plassen — 112 px er den bredeste merkelappen i systemet («Under oppsett»,
     104 px) pluss luft — og bare når raden faktisk har et merke.
     `width: auto` fordi full bredde på et absolutt plassert element ville
     strukket merket over hele kortet. */
  .table tr:has(.tag) td:first-child,
  .table tr:has(.state-dot) td:first-child { padding-right: 112px; }
  .table td:has(.tag), .table td:has(.state-dot) {
    position: absolute; top: 13px; right: 13px; width: auto;
  }

  /* En rad man kan trykke på er hele kortet, og `.tap` gjelder fortsatt:
     44 px er ikke i veien her — kortet er høyere enn det av seg selv. */
  .table tr.tap { min-height: 44px; }
  /* Tall som står høyrestilt i tabellen står venstrestilt i kortet. En kolonne
     er høyrestilt for å kunne sammenlignes nedover; i et kort finnes ikke den
     kolonnen lenger. */
  .table td[style*="right"], .table td[align="right"] { text-align: left; }
}


/* ── 14 · Tom tilstand ──────────────────────────────────────────────────────
   Avgjort 15. august 2026, sammen med punkt 13 og av samme grunn: `0.13` og
   `0.7b` er tegnet, fem tabeller i kundepanelet står uten, og formen treffer
   like mange flater som telefonformen gjør.

   REGELEN FRA 0.7b: **ingen tabellhode over ingenting.** Er lista tom, er det
   ikke en tabell med null rader — det er en setning. Hodet, filterraden og
   søkefeltet står ikke der. De kommer når det finnes noe å filtrere.

   Tre deler, i denne rekkefølgen, og den midterste er den som gjør arbeidet:
     tittelen    hva som ikke finnes, i hennes ord: «Ingen kunder ennå»
     setningen   hvorfor, eller hva som skjer når hun fyller den
     handlingen  ÉN knapp, og den sier hva den lager
   Er det ingenting hun kan gjøre — et søk uten treff — faller knappen bort.
   En knapp som ikke fører noe sted er verre enn ingen knapp.

   `.tom-utkast` er den samme formen inne i redigering, med stiplet kant:
   0.13 sier at en tom blokk SKJULES på publisert side og VISES i redigering
   med hva som mangler. Stiplingen er forskjellen på «her er ingenting» og
   «her kommer noe når du fyller det ut».

   Fargene er målt mot flata under, ikke mot kortet:
     tittel      var(--color-text)            11,9:1 lys ·  12,6:1 mørk
     setningen   var(--color-neutral-800)      7,3:1 lys ·   8,3:1 mørk
     kanten      var(--color-divider)          form, ikke tekst

   Markup:
     <div class="tom">
       <p class="tom-tittel">Ingen kunder ennå</p>
       <p class="tom-hva">Plattformen står, og ingen bor i den.</p>
       <button type="button" class="btn btn-primary">Opprett den første</button>
     </div>
   ───────────────────────────────────────────────────────────────────────── */
.tom {
  display: flex; flex-direction: column; align-items: center;
  gap: var(--space-1);
  padding: var(--space-8) var(--space-6);
  text-align: center;
  background: var(--color-neutral-100);
  border: 1px solid var(--color-divider);
  border-radius: var(--radius-lg);
}
.tom-tittel {
  margin: 0; font-size: 16px; font-weight: 600; color: var(--color-text); /* fulgte body 15 → 16, 24. august */
}
.tom-hva {
  margin: 0; max-width: 40ch;
  font-size: 12.5px; line-height: 1.6;
  color: var(--color-neutral-800);
  text-wrap: pretty;
}
.tom > .btn { margin-top: var(--space-3); }
/* I redigering: stiplet, og på flata siden selv har — den er ikke et kort,
   den er et hull som venter. */
.tom-utkast {
  background: transparent;
  border-style: dashed;
}


/* ── 15 · Romfargene · 0.16 ────────────────────────────────────────────────
   Tegnet 15. august 2026. Erstatter merknaden som sto her og sa at 0.16 ikke
   var tegnet.

   DETTE ER DEN ENE PLASSEN TILLEGGET LEGGER TIL EN FARGE, og det er verdt en
   setning: fila lover i toppen at ingenting her er en ny farge. Løftet gjelder
   fortsatt for alt annet. Romfargen er ikke en ny skrivemåte for noe paletten
   har — den er en ROLLE paletten ikke hadde, og 0-R9 krever at den finnes ETT
   sted. Skrives den ikke her, skrives den i fire filer.

   TRE AV FIRE STO ALLEREDE I KARTET. De er ikke valgt her, de er hentet:

     0-R9   fargen hører til BEHOLDEREN, ikke til rommet
     29a    Kunder er plomme — og `#bd7d5c` (leire) i modulkatalogen utgår
     E9     Booking er nattblå
     og     Butikk må velges på nytt: `#6b7f9c` er nattblås kulør med mer grått

   **Derfor er det fire farger, ikke ti.** En beholder er en modul som har barn.
   Et rom uten beholder har ingen farge — det gjelder Oversikt, Innstillinger,
   Virksomheten, Din avtale, Ditt eget nettsted og Nettstedene dine. Den åpne
   posten «web og portefolje har begge `--color-accent`» lukkes av regelen selv:
   `portefolje` er ikke en beholder, og skal ikke ha farge i det hele tatt.

   TO ER VALGT HER, under E9s krav — ikke grønn, ikke leire, samme lyshet og
   kulørstyrke som de to som sto fast:
     blågrønn   til Web      (kartet navnga kuløren, ingen hadde satt verdien)
     bringebær  til Butikk   (den ene retningen som verken er grønn, leire,
                              plomme eller nattblå)

   MÅLT MOT SIDENS FLATE, ikke mot kortet — romprikken står i sidemenyen, som
   ligger rett på `--color-bg`. Det er den strengeste av de to, og det er den
   som felte `neutral-600` to ganger. Kravet er 3:1: prikken er en form som
   bærer mening.

                     lys drakt              mørk drakt
                     mot bg   mot kort      mot bg   mot kort
     Web             6,06     7,23          7,20     6,42
     Kunder          6,18     7,36          7,11     6,33
     Booking         6,03     7,19          7,29     6,49
     Butikk          6,01     7,17          7,18     6,39

   De fire ligger med vilje på samme lyshet — det er E9s krav, og det er riktig:
   ett rom skal ikke se viktigere ut enn et annet. **Følgen er at de skilles av
   kulør alene, og kulør er det første som forsvinner for den som ser farger
   annerledes.** Derfor står kartets egen setning som en regel her:

   > **Romfargen er aldri det eneste som sier hvilket rom du er i.** Navnet
   > bærer, fargen støtter. En prikk uten et navn ved siden av er en feil.

   I menyen er navnet alltid der. Det ene stedet prikken står alene, er på det
   ensomme punktet — raden som ER sin egen beholder. Der bærer radens eget navn
   meningen, og prikken sier bare hvilket rom raden hører til.

   Ingen fil skriver en romfarge selv. Den leses herfra. (R2.)
   ───────────────────────────────────────────────────────────────────────── */
/* Den lyse paletten henger på BEGGE: roten, og et undertre som sier at det er lyst.
   Uten det andre leddet arver en lys drakt inne i siden de mørke verdiene den dagen
   maskinen står i mørk modus — `:not([data-drakt="lys"])` beskytter elementet regelen
   treffer, aldri etterkommerne. Tegningene våre viser lys og mørk side om side, så
   dette er ikke et kanttilfelle her; det er hovedtilfellet. */
:root, [data-drakt="lys"] {
  --color-rom-web:     #1f5d5d;   /* blågrønn  */
  --color-rom-crm:     #5b4b7a;   /* plomme    */
  --color-rom-booking: #37567f;   /* nattblå   */
  --color-rom-butikk:  #8a3a52;   /* bringebær */
}
[data-drakt="mork"] {
  --color-rom-web:     #78b1ad;
  --color-rom-crm:     #b09ec9;
  --color-rom-booking: #8daad0;
  --color-rom-butikk:  #d097a6;
}


/* ── 16 · Beholderbreddene · 0.3c ───────────────────────────────────────────
   Avgjort 22. august 2026. Det ene åpne punktet i «Uavklart i 0» er lukket:
   BREDDESTIGEN GJELDER PANELENE, ikke bare kundenes nettsteder. Tallene selv
   ble godkjent 12. august, og «1080 blir stående som beholder» er ordrett
   derfra.

   Bekreftet i valgtabellen i 0.3c før de ble skrevet, fordi kartet navnga
   bare 1080: Normal 1080 · Bred 1320 · Kant til kant 1440. Bred er der
   «rutenett med tre og fire spalter, bilderader, tabeller», og Kant til kant
   er «hele flaten, innhold stopper på 1440».

   G2 målte 17. august at ingen av tallene fantes i noe stilark. Tre andre
   står fortsatt uskrevet — 720, 900 og 1180, spaltestigen i 0.3d. De er
   IKKE i denne blokka: de svarer på hvor mange spalter, ikke hvor bred
   beholderen er, og de hører sammen med beholderspørringene i punkt 13 den
   dagen de skrives.

   BREDDENE ER LIKE I BEGGE DRAKTER, og derfor står de i sin egen `:root` og
   ikke i paletten. **De skal ikke speiles i @media-blokka nederst i fila.**
   Den blokka finnes fordi drakta kan komme fra maskinen; en bredde kommer
   ikke fra maskinen. Skrives de inn der også, er det to sannheter om samme
   tall, og den ene blir glemt.

   TOKENENE ER TAK, IKKE BREDDER. 0.3c: «Spalter, bredde og luft er høyeste
   verdi, ikke fast verdi. Systemet reduserer, aldri motsatt.» Derfor
   `max-width` der de brukes, aldri `width`.

   Kant til kant har ingen bredde på selve blokka — flaten er hele bredden.
   `--width-bleed` er taket på INNHOLDET inne i en slik blokk, og det er hele
   grunnen til at det er et eget tall og ikke bare «ingen bredde».

   SIDEMARGEN, RETTET 23. AUGUST. Setningen som sto her var feil i sitt eget
   tall: **`--space-8` er 32, ikke 48.** Skalaen er 4 · 8 · 12 · 16 · 24 · 32,
   og 48 finnes ikke i den. Det er formen R29 er skrevet for — et tall skrevet
   i stedet for lest — og det sto i kommentaren som lover at ingen nye tokens
   trengs.

   **Avgjort: sidemargen er 24 på telefon og 32 på bred skjerm.** `--space-6`
   og `--space-8`, som setningen påsto. 0.3cs «48» ble skrevet før skalaen
   fantes, og en margin som krever et token ingen annen regel bruker er en
   margin oppfunnet for én regel. **Skal det bli 48, er det `--space-12` og en
   ny rad i skalaen** — og da er det den avgjørelsen, ikke denne.

   OG PRESEDENSEN, SOM ER DET BYGGET SPURTE OM. På 1440 møtes ikke stigen og
   margen, og en av de to må gi etter. **Margen vinner. Stigen gir.**

   Grunnen står tre avsnitt opp i dette punktet: *tokenene er tak, ikke
   bredder. Systemet reduserer, aldri motsatt.* **Et tak som reduseres gjør
   nøyaktig det det er skrevet for. En minsteverdi som reduseres er ikke en
   minsteverdi.** Derfor: innholdet stopper på `min(trinnet, 100% − 2 × margen)`,
   og gulvet på 16 trengs ikke — det kan ikke nås når margen er den som holder.

   Bygget lot stigen vinne med et gulv på 16, som en midlertidig avgjørelse med
   utløper. **Det var riktig håndtert og motsatt vei av dette**, og utløperen er
   nå løpt ut.
   ───────────────────────────────────────────────────────────────────────── */
:root {
  --width-normal: 1080px;   /* standard · skjema, kort, lister, de fleste blokker */
  --width-wide:   1320px;   /* rutenett med tre og fire spalter, bilderader, tabeller */
  --width-bleed:  1440px;   /* taket på innholdet i en kant-til-kant-blokk */
}


/* ── 17 · Lesemålet · 0.3c-rettelse 1 ───────────────────────────────────────
   Rettelse 1 av 12. august, ordrett: «brødtekst i én spalte går aldri over
   rundt 70 tegn, uansett hvor lang teksten er.»

   DE TO TALLENE I PUNKT 16 OG HER SIER IKKE DET SAMME, og det er hele
   poenget. 1080 ble stående som beholder, og 1080 gir 110–120 tegn på linja.
   **Beholderen er en bredde. Lesemålet er en egenskap ved teksten.** Det var
   feilen rettelsen rettet: en terskel som ventet på at teksten skulle bli
   lang nok, i stedet for et mål som gjelder uansett.

   G2 målte 17. august at regelen ikke fantes i noen fil. I dag står den
   håndskrevet ett sted — `max-width: 64ch` på begrunnelseslinja i modulraden.
   Ett tall, ett sted, flere lesninger: det er formen R2 finnes for.

   `ch` OG IKKE PIKSLER. En linje måles i tegn. `ch` er bredden på «0», og
   løpende tekst har smalere gjennomsnitt enn det, så 70ch rommer litt mer
   enn sytti tegn. Avviket går med vilje den retningen: 0.3c sier «rundt 70»,
   og litt for langt er en bedre feil enn en spalte på seksti tegn som
   brekker en setning som skulle stått på én linje.

   REGELEN STÅR PÅ ELEMENTET, IKKE PÅ EN KLASSE. Det er den eneste måten
   «uansett hvor lang teksten er» kan bli sant. En klasse er noe den neste
   kan glemme å få med, og den som glemmer den oppdager ingenting — avsnittet
   ser riktig ut, det er bare for bredt. Samme begrunnelse som tabellformen
   lenger opp i fila: en regel som må huskes blir brutt, en regel som følger
   av strukturen blir ikke.

   DET ER ET TAK. Et avsnitt i en spalte på 300 px er urørt; regelen biter
   bare der linja ellers ville blitt lang. Derfor kan den stå globalt uten å
   gjøre om et eneste oppsett.

   TO KLASSER, OG BEGGE ER NØDVENDIGE:
     `.measure`       brødtekst som ikke er et <p> — en <div> med en
                      ledetekst, et <li> som er en hel setning
     `.measure-none`  det ene avsnittet som ER et layoutledd og ikke en
                      tekst. Den finnes for å slippe `style="max-width:none"`
                      spredt utover flatene.

   SMALERE MÅL ER IKKE FEIL. En begrunnelse under et navn, en bildetekst, en
   setning i en smal kolonne — de følger SIN kolonne, ikke lesemålet.
   `.tom-hva` i punkt 14 står på 40ch og blir stående: to sentrerte linjer er
   ikke løpende tekst. Det som ikke skal finnes, er fem ulike håndskrevne
   tall for det samme målet.
   ───────────────────────────────────────────────────────────────────────── */
:root { --measure: 70ch; }
p { max-width: var(--measure); }
.measure { max-width: var(--measure); }
.measure-none { max-width: none; }


/* ── 18 · Døren · venstremenyen i eierdøren ─────────────────────────────────
   Flyttet hit 23. august fra `I Eierdoren.dc.html`s eget stilark. Åtte
   klassenavn sto i én tegningsfil og bar med én gang sju skjermer — `.dr`,
   `.mny`, `.mnyhd`, `.mnyl`, `.mp2`, `.mnyf`, `.drh`, `.kolinje`. Det er
   formen punkt 8 og 10 ble skrevet for: **en form som brukes av mer enn én
   flate er ikke en lokal form lenger**, og den som kopierer tegningen kopierer
   da åtte erklæringer i stedet for å arve dem.

   322 OG 46 ER IKKE NYE TALL. De er `--skuff` og `--skuffrad`, de samme to
   tallene rommenes skuff i kundepanelet bruker under 55 rem. Døren er den
   samme menyen uten bruddet på 55 — derfor står tallene her som de er, og
   ikke som en ny stige. Skrives de som tokener, er det på skuffens side av
   huset, og da flytter begge.

   MENYEN ER RAMME, IKKE INNHOLD. Den bærer ingen av skjermens data og er lik
   på hver skjerm. Derfor ligger den UTENFOR breddetrinnet i punkt 16: 1320 er
   fortsatt 1320 der innholdet leses, og rammen blir 1642. Det er hele grunnen
   til at `.drh` bare er `min-width: 0` — spalten må kunne krympe under
   innholdets naturlige bredde, ellers skyver en bred tabell menyen ut av
   skjermen i stedet for å bli smal selv.

   `.mp2.kmr` ER ET MERKE, IKKE EN TILSTAND. Sju av tolv punkter finnes ikke i
   den bygde døren ennå. Uten merket er den samme tegningen en bestilling på
   sju lenker til ingenting — og merket er R19 gjort mekanisk: det forsvinner
   den dagen punktet finnes, og ingen trenger å huske å fjerne det.

   KØEN STÅR UTENFOR MENYEN — `I-R13`. `.kolinje` ligger over innholdet og
   aldri i menyen: inne i en meny som kan lukkes er «Stopp» ett trykk unna å
   ikke finnes. Samme begrunnelse som skuffen på 390 px.
   ───────────────────────────────────────────────────────────────────────── */
.dr { display: grid; grid-template-columns: 322px minmax(0, 1fr); align-items: stretch; }
.mny {
  border-right: 1px solid var(--color-divider); background: var(--color-surface);
  display: flex; flex-direction: column;
}
.mnyhd { padding: 13px 17px 12px; border-bottom: 1px solid var(--color-divider); }
.mnyl { display: flex; flex-direction: column; padding: 7px 0; flex: 1; }
.mp2 {
  min-height: 46px; display: flex; align-items: center; gap: 9px; padding: 0 17px;
  border-left: 3px solid transparent;
  font: 500 13.5px var(--font-body); color: var(--color-text-muted);
}
.mp2.on {
  border-left-color: var(--color-accent); color: var(--color-text);
  font-weight: 600; background: var(--color-neutral-100);
}
.mp2.kmr { border-left: 3px dashed var(--color-accent-2); color: var(--color-accent-2-800); }
.mnyf {
  border-top: 1px solid var(--color-divider); padding: 12px 17px 14px;
  display: flex; flex-direction: column; align-items: flex-start; gap: 7px;
}
.drh { min-width: 0; }
.kolinje {
  display: flex; align-items: center; gap: 10px; padding: 9px 16px;
  border-bottom: 1px solid var(--color-divider);
  background: var(--color-accent-2-100); flex-wrap: wrap;
}
.kolinje .k { font: 600 12px var(--font-body); color: var(--color-accent-2-800); }



/* ── NAVNESAMMENFALL · fire klassenavn som alt er elementnavn ─────────────────
   Funnet av navneregisteret 22. august, vakt 2: `.input`, `.nav`, `.select` og
   `.table` er ord HTML alt eier. Det er samme form som `label`: **ordet var
   opptatt før noen valgte det som klassenavn, og derfor så ingen det.**

   DE FIRE BLIR STÅENDE. Å døpe om fire navn i 46 tegninger, dette arket og
   repoet er en stor endring uten en eneste virkning — og i perioden mellom
   første og siste fil ville begge navn vært sanne samtidig. Det er R2, innført
   av en opprydding.

   DET SOM FAKTISK KAN LESES FEIL ER IKKE NAVNET. Det er om klassen sitter på
   elementet som har samme navn, og der skiller de fire seg:

     .table   sitter PÅ <table>.  Samme ord, samme ting. Ufarlig.
     .nav     sitter PÅ <nav>.    Samme ord, samme ting. Ufarlig.
     .input   sitter på <input>, <textarea> OG <select>. Den navngir en
              ROLLE — et felt — og ikke et element. Derfor er den harmløs:
              `textarea.input` leser riktig fordi klassen aldri lovet <input>.
     .select  sitter ALDRI på <select>. Den er på <div>-en RUNDT feltet, og
              feltet inni bærer `.input`. **Det er den ene som kan leses feil**,
              og den leses feil i én linje her i fila: `.select select.input`
              ser ut som en tautologi og betyr «feltet inne i innpakningen».

   REGELEN VIDERE: **et nytt klassenavn skal ikke ta et elementnavn.** De fire
   over er arvet og navngitt her; de er unntakene, ikke mønsteret.

   Og når en regel gjelder både elementet og klassen, skal den kvalifiseres —
   `table.table`, `div.select` — så leseren ser hvilken av de to som menes.
   ───────────────────────────────────────────────────────────────────────── */


/* ── HUSREGEL · en verdi som er målt for en form, er ikke målt for tekst ─────
   Funnet og formulert av design 14. august, og den er den skarpeste i fila.

   `--color-neutral-600` er RIKTIG for tilstandsprikken i punkt 11 og for
   av-sporet i punkt 3. Der er tingen en form, og gulvet er 3:1.

   Den samme verdien er FEIL på 10 px tekst, der gulvet er 4,5:1.

   Det er ikke to sannheter. **Det er én verdi brukt til to formål, med to
   ulike krav.** Det er en egen feilform, og den ser ut som riktig bruk helt
   til noen måler den mot riktig krav.

   Praktisk:
     form som bærer mening (prikk, spor, kant, ikon)   3:1
     tekst under 18 px                                  4,5:1
     tekst 18 px og over, eller 14 px fet               3:1

   Et token har derfor ikke ett gulv. **Gulvet hører til bruken, ikke til
   fargen.** Kommentarene i denne fila oppgir derfor hva som ble målt MOT, og
   ikke bare tallet.
   ───────────────────────────────────────────────────────────────────────── */


/* ── Drakta og maskinens eget valg ──────────────────────────────────────────
   Skrevet 15. august 2026, og den er en RETTELSE av arbeidsdelingen mer enn av
   fila: plattformen utledet denne blokka av `[data-drakt="mork"]` ved oppstart
   — en maskin som skrev om stilarket hver gang det ble levert. Blokka står her
   nå, og den maskinen kan slettes.

   To steder drakta kan slå til, og bare to:
     [data-drakt="mork"]                  vi har bestemt det, eller hun har
     prefers-color-scheme + :not([lys])   maskinen hennes har bestemt det, og
                                          ingen har overstyrt det

   `:root:not([data-drakt="lys"])` er hele grepet: har hun valgt LYS selv, skal
   maskinens mening ikke overkjøre henne. Har hun ikke valgt noe, følger vi
   maskinen.

   OG DET ER IKKE BARE TOKENENE. Fem komponentregler henger på drakta — blant
   annet at primærknappen snur til mørk skrift. Speiles bare fargene, får den
   som har mørk drakt fra maskinen en grønn knapp med hvit skrift, og den er
   målt til å ikke holde. Derfor står HVER regel som henger på drakta her.

   VERDIENE ER DE SAMME, OG DE SKAL FORBLI DET. Endres én, endres begge.
   Prøven kan skrives, og bør: sett drakta med attributtet, les `--color-bg`;
   sett den med maskinvalget, les den igjen. Samme svar, og like mange regler.
   ───────────────────────────────────────────────────────────────────────── */
@media (prefers-color-scheme: dark) {
  :root:not([data-drakt="lys"]) {
    --color-bg: #1b1a17;
    --color-surface: #26241f;
    --color-text: #f7f5f0;
    --color-divider: #3a362f;
    --color-field-border: #8b8477;  /* 4,2:1 mot surface · 4,7:1 mot bg */
    --color-text-muted: #b3ada1;    /* 7,0:1 mot surface · 8,1:1 mot bg */
    --color-accent: #9dc4ac;
    --color-accent-2: #d3a385;

    --color-neutral-100: #26241f;
    --color-neutral-200: #302d27;
    --color-neutral-300: #3a362f;
    --color-neutral-400: #4a463f;
    --color-neutral-500: #6d675d;
    --color-neutral-600: #8b8477;
    --color-neutral-700: #a8a193;
    --color-neutral-800: #cfc8ba;
    --color-neutral-900: #f7f5f0;

    --color-accent-100: #22302a;
    --color-accent-200: #2b3f35;
    --color-accent-300: #3a5748;
    --color-accent-400: #5d8e72;
    --color-accent-500: #7fae91;
    --color-accent-600: #b4d4c0;
    --color-accent-700: #cbe2d4;
    --color-accent-800: #e2f0e8;
    --color-accent-900: #f2f8f4;

    --color-accent-2-100: #33251d;
    --color-accent-2-200: #432f24;
    --color-accent-2-300: #5c4131;
    --color-accent-2-400: #8a5239;
    --color-accent-2-500: #bd7d5c;
    --color-accent-2-600: #d3a385;
    --color-accent-2-700: #e2bfa8;
    --color-accent-2-800: #f0d9c8;
    --color-accent-2-900: #f8ece2;

    /* På mørk flate bærer ikke skygge. Hevet flate markeres med en lysere
       kant, og skyggen holdes bare som ambient dybde under dialoger. */
    --shadow-sm: 0 0 0 1px #302d27;
    --shadow-md: 0 0 0 1px #3a362f, 0 4px 14px rgb(0 0 0 / 0.35);
    --shadow-lg: 0 0 0 1px #3a362f, 0 16px 40px rgb(0 0 0 / 0.5);
  }

  :root:not([data-drakt="lys"]) {
   background: var(--color-bg); color: var(--color-text); 
  }

  :where(:root:not([data-drakt="lys"])) .btn-primary:where(:not([data-drakt="lys"] *)) {
   color: #1b1a17; 
  }

  :where(:root:not([data-drakt="lys"])) .btn-primary:hover:where(:not([data-drakt="lys"] *)) {
   background: var(--color-accent-600); 
  }

  :where(:root:not([data-drakt="lys"])) .btn-primary:active:where(:not([data-drakt="lys"] *)) {
   background: var(--color-accent-700); 
  }

  :where(:root:not([data-drakt="lys"])) .seg-opt:has(input:checked):where(:not([data-drakt="lys"] *)) {
   color: #1b1a17; 
  }

  :where(:root:not([data-drakt="lys"])) .radio input:checked + .dot:where(:not([data-drakt="lys"] *)) {
   box-shadow: inset 0 0 0 4px var(--color-bg); 
  }

  :root:not([data-drakt="lys"]) {
    --color-rom-web:     #78b1ad;
    --color-rom-crm:     #b09ec9;
    --color-rom-booking: #8daad0;
    --color-rom-butikk:  #d097a6;
  }
}
