/* =====================================================================
   app.css — eneste stylesheet. Alle værdier fra DESIGN.md.
   Ingen hex-værdier uden for :root.

   ---------------------------------------------------------------------
   HALE-ORDEN (lov). Filen er tre stablede stylesheets plus en hale.
   Rapportlaget overskriver app-skallen ved POSITION, ikke ved
   specificitet — derfor må rækkefølgen aldrig laves om, og ny CSS må kun
   lægges sidst i sin egen sektion:

     1. App-skallen ........ reset, layout, topbar, sidebar, komponenter
     2. Kunderapporten ..... .report-*  (dokumentet der printes)
     3. Sagsoverblikket .... .case-bar, .stat-*, .section-head, .case-cols
     4. Dataviz ............ .dv, .cell-bar
     5. @media print
     6. @media prefers-reduced-motion   ← ALTID sidst, ellers dækker den
                                          ikke det der står efter den

   ---------------------------------------------------------------------
   BRUDPUNKTER. Der findes seks. Opfind ikke flere — genbrug det nærmeste.
   (CSS custom properties virker ikke i media queries uden byggetrin, så
   de kan ikke samles ét sted. Denne tabel er registret.)

     1100px  .grid-2 og .case-cols falder til én kolonne
      900px  rapportens grid falder sammen
      768px  sidebaren bliver til en skuffe; app'en bliver énkolonnet
      640px  sagsoverblikkets polstring og tabelhøjder strammes
      560px  rapportarket går kant til kant på telefon
      400px  nøgletal og sagsbånd falder til én kolonne

   ---------------------------------------------------------------------
   FARVEBUDGETTER. Tre adskilte, og de må ikke blandes:

     --accent .......... INTERAKTION. Kun det man klikker på.
     status ............ DOM. Godt, advarsel, dårligt.
     --series-N ........ MÆNGDE. Kurver, søjler, ringe, andele.

   En orange kurve konkurrerer med hver knap på skærmen; en grøn siger
   "det her er godt" før nogen har læst tallet. Derfor den tredje palet.
   ===================================================================== */

:root {
  /* Native formularkontroller skal ikke auto-mørknes af browseren, og en
     senere mørk tilstand skal være en kontakt frem for en kamp. */
  color-scheme: light;

  /* Flader */
  --bg-page:        #F1F1F0;
  --bg-surface:     #FFFFFF;
  --bg-card:        #FFFFFF;   /* samme som --bg-surface, men navngivet til kort */
  --bg-sidebar:     #FAFAF9;
  --bg-subtle:      #F5F5F4;
  --bg-inset:       #EFEEED;
  /* Hover skal ALTID være ét trin mørkere end fladen den ligger på.
     Før lå hover på --bg-subtle (#F5F5F4), som er LYSERE end zebra-rækkens
     --bg-inset (#EFEEED) — derfor forsvandt hover på hver anden tabelrække. */
  --bg-hover:       #EAE9E7;

  /* Streger */
  --border:         #E7E6E4;
  --border-strong:  #D6D5D2;

  /* Tekst */
  --text:           #2B2A28;
  --text-body:      #4A4845;
  /* Var #8A8783 — 3,4:1 på hvidt, under gulvet på 4,5:1 og årsagen til at
     labels, hjælpetekst og korttællere overalt læste som "gråt i gråt".
     Mørknet ét trin: 5,3:1 på hvidt, 4,9:1 på --bg-subtle, 4,6:1 på
     --bg-inset. Stadig tydeligt sekundær i forhold til --text-body (8,4:1). */
  --text-muted:     #6F6C68;
  --text-faint:     #C2BFBB;

  /* Accent */
  --accent:         #F4511E;
  --accent-hover:   #DC4416;
  --accent-soft:    #FDECE6;
  --accent-line:    #F5876A;
  --accent-fill:    rgba(245, 135, 106, 0.14);

  /* Status */
  --danger:         #E8557A;
  --danger-soft:    #FDEBEF;
  --warn:           #E07B39;
  --warn-soft:      #FCF0E6;
  --success:        #22A06B;
  --success-soft:   #E8F5EF;

  /* Status som tekst. De lyse statusfarver har for lav kontrast på hvidt til
     brødtekst (under 4,5:1) — disse er de samme farver mørknet, så en grøn
     eller rød sætning kan læses. Fladerne bruger stadig varianterne ovenfor. */
  --danger-ink:     #C42A52;
  --warn-ink:       #A85419;
  --success-ink:    #167A50;
  --accent-ink:     #C2390D;   /* accent som tekst på --accent-soft: 4,7:1 */

  /* Forgrund på farvet flade. Var hardkodet #FFF tre steder. */
  --on-accent:      #FFFFFF;

  /* Slør bag mobilmenuen. Var rå rgba i .nav-scrim. */
  --scrim:          rgba(30, 28, 26, .35);

  /* Form */
  --radius-xs:      2px;       /* datamærker: skinner, søjler, streger */
  --radius-sm:      6px;
  --radius:         10px;
  --radius-lg:      14px;
  --radius-pill:    999px;

  /* Højdestige. Fire niveauer, ikke spredte skygger:
       0  fladt      indhold i et kort, zebra-rækker, .prompt-box
       1  --shadow-sm  hvilende flader: .card, .stat-grid, .case-bar
       2  --shadow-md  flader der vil ses på: kort med graf, løftet link-kort
       3  --shadow-lg  ting der svæver over siden: menuer, tooltips
     DESIGN.md's gamle "ingen skygge på kort" er ophævet: hvidt på næsten-
     hvidt med 1px kant giver ~2 % kontrast, og så flyder intet. */
  --shadow-xs:      0 1px 2px rgba(30, 28, 26, 0.05);
  --shadow-sm:      0 1px 2px rgba(30, 28, 26, 0.04),
                    0 1px 3px rgba(30, 28, 26, 0.05);
  --shadow-md:      0 2px 4px rgba(30, 28, 26, 0.05),
                    0 6px 16px -4px rgba(30, 28, 26, 0.08);
  --shadow-lg:      0 8px 24px rgba(30, 28, 26, 0.10);
  --shadow-pop:     var(--shadow-lg);   /* gammelt navn, samme værdi */

  /* Serie-palet — MÆNGDE, aldrig dom. Adskilt fra statusfarverne med vilje.
     Kun til flader og streger: WCAG-gulvet for grafiske objekter er 3:1, og
     alle fem klarer det på hvidt. Ingen tekstetiket må tage en seriefarve —
     --series-3 ligger på 3,6:1 og er for lidt til brødtekst. */
  --series-1:       #3E6FB0;   /* klik */
  --series-2:       #7A5EA8;   /* eksponeringer */
  --series-3:       #2F8F83;   /* klikrate */
  --series-4:       #B07A2B;   /* placering */
  --series-5:       #8C6E63;   /* øvrige, rest */
  --series-1-soft:  rgba(62, 111, 176, 0.16);
  --series-2-soft:  rgba(122, 94, 168, 0.16);
  --series-3-soft:  rgba(47, 143, 131, 0.16);
  --series-4-soft:  rgba(176, 122, 43, 0.16);
  --series-5-soft:  rgba(140, 110, 99, 0.16);
  --data-ink:       var(--text-body);   /* søjle uden dom */
  --data-track:     var(--bg-inset);    /* den umålte del af en skinne */

  /* Spacing */
  --sp-1: 4px;  --sp-2: 8px;  --sp-3: 12px; --sp-4: 16px;
  --sp-5: 20px; --sp-6: 24px; --sp-8: 32px; --sp-10: 40px;

  /* Typografi */
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, Roboto,
          "Helvetica Neue", Arial, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;

  /* To typetrin ud over det almindelige. Ikke et fuldt type-token-system —
     det ville røre 200 regler uden at ændre noget. */
  --fs-hero:        44px;      /* ét tal pr. skærm */
  --fs-display:     34px;      /* næststørste tal */

  /* Bevægelse. Samme tal som før, nu med navne — det er dét der gør
     reduced-motion bevisbart frem for tilfældigt. */
  --dur-1:          120ms;     /* farve og baggrund ved hover */
  --dur-2:          180ms;     /* løft, søjlevækst, paneler */
  --dur-3:          320ms;     /* indtoning af en flash-bjælke */
  --dur-chart:      560ms;     /* kurve der tegnes ind — én gang */
  --ease:           cubic-bezier(.2, .7, .3, 1);
  --ease-out:       cubic-bezier(.16, 1, .3, 1);

  /* Mål */
  --sidebar-w: 240px;
  --sidebar-w-collapsed: 64px;
  --topbar-h: 64px;
}

/* --- Reset --------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

html, body { height: 100%; }

body {
  margin: 0;
  background: var(--bg-page);
  color: var(--text-body);
  font: 400 14px/1.55 var(--font);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4, p, figure { margin: 0; }
ul, ol { margin: 0; padding: 0; }

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

button, input, select, textarea { font: inherit; color: inherit; }

.icon { flex: none; display: block; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* --- Layout -------------------------------------------------------- */

.app {
  display: grid;
  grid-template-columns: var(--sidebar-w) 1fr;
  min-height: 100vh;
  transition: grid-template-columns var(--dur-2) var(--ease);
}
.app.is-collapsed { grid-template-columns: var(--sidebar-w-collapsed) 1fr; }

.main { min-width: 0; display: flex; flex-direction: column; }

.content {
  width: 100%;
  max-width: 1360px;
  margin: 0 auto;
  padding: var(--sp-6);
}

.page-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--sp-4);
  margin-bottom: var(--sp-5);
}
/* Sidetitlen vejede det samme som inventaret omkring den. */
.page-title {
  font-size: 24px; font-weight: 600;
  letter-spacing: -0.02em;
  color: var(--text);
}
.page-sub   { font-size: 14px; color: var(--text-muted); margin-top: var(--sp-1); }
.page-sub strong { font-weight: 600; color: var(--text); }
.page-actions { display: flex; gap: var(--sp-2); flex: none; }

.grid-2 {
  display: grid;
  grid-template-columns: 2fr 1fr;
  gap: var(--sp-5);
  align-items: start;
}

/* Grid-børn har som standard min-width: auto, så et bredt element (fx en
   9-kolonners tabel fra AI-svaret) presser sit spor bredere end 2fr og
   skubber højre kolonne ud af skærmen. min-width: 0 lader sporet krympe,
   så .table-wrap's overflow-x: auto i stedet giver tabellen sin egen scroll. */
.grid-2 > * { min-width: 0; }

/* Afstanden inde i et grid kommer fra gap, men to blokke i træk rørte
   hinanden: .card + .card fanger dem ikke, når naboen er et grid. */
.grid-2 + .grid-2,
.grid-2 + .card,
.card + .grid-2 { margin-top: var(--sp-5); }

/* To lige kolonner. Til rækker hvor de to kort vejer det samme — 2fr/1fr
   presser ellers indholdet i højre kolonne unødigt sammen. */
.grid-2--even { grid-template-columns: 1fr 1fr; }

/* .grid-stats stod her indtil fase 8. Den var en tredje måde at stille
   nøgletal op på ved siden af .stat-grid og .stat-grid--cards, og dens
   sidste bruger (reminders.php) er skrevet om til .stat-grid--cards. */

/* Afstanden i et grid kommer fra gap. Uden dette ville .card + .card
   længere nede skubbe alle kort efter det første 20px ned. */
.grid-2 > .card + .card { margin-top: 0; }

/* --- Bento: dashboardets fliselag ---------------------------------- */

/* Tolv spor, så en flise kan spænde 8, 4 eller 3 og rækkerne stadig flugte.
   Kolonnerne er tættere end rækkerne (--sp-4 mod --sp-5) med vilje: fliser i
   SAMME række skal læses som ét instrument, mens to rækker er to emner.
   Brudpunkterne er de eksisterende — der opfindes ingen nye. */
.bento {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: var(--sp-5) var(--sp-4);
  align-items: start;
  margin-bottom: var(--sp-5);
}
.bento > * { min-width: 0; }

.bento__8 { grid-column: span 8; }
.bento__4 { grid-column: span 4; }
.bento__3 { grid-column: span 3; }
.bento__full { grid-column: 1 / -1; }

/* Afstanden i et grid kommer fra gap. Uden disse to ville .card + .card
   (samme specificitet, men længere nede i filen) lægge 20px oven på hver
   flise der har et kort som nabo, og rækken ville stå trappeformet.
   En nøgletalsramme bærer af samme grund ikke sin egen bundmargen her. */
.bento > .card + .card { margin-top: 0; }
.bento .stat-grid { margin-bottom: 0; }

/* Og den anden vej: bentoen er et grid, ikke et kort, så .card + .card
   fanger den ikke når den står som nabo til et almindeligt kort. Uden dette
   ligger første fliserække klods op ad kortet ovenover. Samme hul som
   .grid-2 havde (se :258). --sp-5 er den samme afstand som mellem to kort —
   en fliserække er et nyt emne, ikke en ny slags afstand. */
.card + .bento,
.bento + .card { margin-top: var(--sp-5); }

/* --- Topbar -------------------------------------------------------- */

.topbar {
  position: sticky; top: 0; z-index: 20;
  height: var(--topbar-h);
  display: flex; align-items: center; gap: var(--sp-4);
  padding: 0 var(--sp-6);
  background: var(--bg-surface);
  border-bottom: 1px solid var(--border);
}

.topbar-search {
  position: relative;
  flex: 1 1 auto;
  max-width: 480px;
  margin: 0 auto;
}
.topbar-search .icon {
  position: absolute; left: 12px; top: 50%;
  transform: translateY(-50%);
  color: var(--text-muted);
  pointer-events: none;
}
.topbar-search input {
  width: 100%;
  padding: 10px 12px 10px 38px;
  background: var(--bg-subtle);
  border: 1px solid transparent;
  border-radius: var(--radius);
}
.topbar-search input:focus {
  background: var(--bg-surface);
  border-color: var(--accent);
  outline: none;
}

/* Skrives med .topbar-prefiks, så .btn længere nede ikke overtrumfer den. */
.topbar .nav-toggle { display: none; }

/* --- Sidebar ------------------------------------------------------- */

.sidebar {
  position: sticky; top: 0;
  height: 100vh;
  display: flex; flex-direction: column;
  background: var(--bg-sidebar);
  border-right: 1px solid var(--border);
  padding: var(--sp-4) var(--sp-3);
}

/* Scroll ligger på nav, ikke på .sidebar — ellers klipper overflow den
   runde fold-knap, der stikker 12px ud over sidebar-kanten. */
.sidebar nav { flex: 1; min-height: 0; overflow-y: auto; }

.sidebar-brand {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3) var(--sp-5);
  font-size: 15px; font-weight: 600; color: var(--text);
  text-decoration: none;
}
.sidebar-brand:hover { text-decoration: none; }
.sidebar-brand .icon { color: var(--accent); }

.nav-group { margin-bottom: var(--sp-4); }
.nav-group-title {
  display: flex; align-items: center; justify-content: space-between;
  width: 100%;
  padding: var(--sp-2) var(--sp-3);
  background: none; border: 0; cursor: pointer;
  font-size: 12px; font-weight: 500; color: var(--text-muted);
  text-align: left;
}
.nav-group-title .icon { transition: transform var(--dur-2) var(--ease); }
.nav-group.is-folded .nav-group-title .icon { transform: rotate(-90deg); }
.nav-group.is-folded .nav-list { display: none; }

.nav-list { list-style: none; }
/* Dashboard står alene over den første gruppe og skal have luft ned til den */
.nav-list--top { margin-bottom: var(--sp-4); }

/* Fixed også på desktop, så scrim aldrig bliver et grid-item i .app
   (det ville skubbe .main ned i næste række). */
.nav-scrim {
  position: fixed; inset: 0;
  background: var(--scrim);
  z-index: 45;
}
.nav-scrim[hidden] { display: none; }

.nav-link {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: 10px 12px;
  border-radius: var(--radius);
  color: var(--text-body);
  font-size: 14px;
  text-decoration: none;
  transition: background var(--dur-1) var(--ease);
}
.nav-link:hover { background: var(--bg-subtle); text-decoration: none; }
.nav-link .icon { color: var(--text-muted); }
.nav-link.is-active {
  background: var(--bg-subtle);
  color: var(--text);
  font-weight: 500;
}
.nav-link.is-active .icon { color: var(--text); }

/* Rund knap på kanten mellem sidebar og indhold */
.sidebar-collapse {
  position: absolute;
  top: 78px; right: -12px;
  width: 24px; height: 24px;
  display: grid; place-items: center;
  background: var(--accent);
  color: var(--on-accent);
  border: 0; border-radius: 50%;
  cursor: pointer;
  z-index: 30;
  box-shadow: var(--shadow-sm);
}
.sidebar-collapse:hover { background: var(--accent-hover); }
.sidebar-collapse .icon { transition: transform var(--dur-2) var(--ease); }
.app.is-collapsed .sidebar-collapse .icon { transform: rotate(180deg); }

.app.is-collapsed .sidebar { padding-left: var(--sp-2); padding-right: var(--sp-2); }
.app.is-collapsed .nav-label,
.app.is-collapsed .nav-group-title span,
.app.is-collapsed .sidebar-brand span { display: none; }
.app.is-collapsed .nav-link { justify-content: center; padding: 10px; }
.app.is-collapsed .nav-group-title { justify-content: center; }

/* --- Kort ---------------------------------------------------------- */

/* Højdeniveau 1. Hvidt kort på næsten-hvid side med kun en 1px kant giver
   ~2 % kontrast — intet flyder, og siden læses som ét fladt ark papir. */
.card {
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--sp-5);
  box-shadow: var(--shadow-sm);
}
.card + .card { margin-top: var(--sp-5); }
.card--flush { padding: 0; overflow: hidden; }
/* Et kort der bærer læsetekst frem for data. Ubegrænset bredde giver 150
   tegn pr. linje på en bred skærm, og øjet mister linjen på vej tilbage. */
.card--narrow { max-width: 860px; }

/* Et kort med et id er målet for et anker. Topbaren er sticky, så uden dette
   lander springet med korthovedet gemt bag den, og man tror man ramte
   forkert. Gælder alle sidens ankre, ikke kun sagssidens håndtag. */
.card[id], .section-head[id], .stat-grid[id] { scroll-margin-top: calc(var(--topbar-h) + var(--sp-4)); }

.card-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-4);
  margin-bottom: var(--sp-4);
}
.card--flush .card-head { padding: var(--sp-5) var(--sp-5) var(--sp-4); margin: 0; }
.card-title {
  font-size: 15px; font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--text);
}
.card-meta  { font-size: 12px; color: var(--text-muted); }

/* Højdeniveau 2: kort der bærer en tegning. Det flyder frem for at være
   tegnet med en streg, og får mere luft — en graf klemt ud til kanten
   læses som en fejl. Kanten fjernes, ellers konkurrerer den med skyggen. */
.card--data {
  padding: var(--sp-6);
  border-color: transparent;
  box-shadow: var(--shadow-md);
}

/* Kun KLIKBARE kort løfter sig. Sagssiden har 26 kort — hvis de alle
   reagerede på markøren, ville siden bevæge sig hele tiden.
   Ingen transform på et kort der indeholder en tabel: en transform på en
   forfader dræber position: sticky, og så holder tabelhovedet op med at
   sidde fast. Link-kort indeholder aldrig tabeller. */
.card--link { display: block; color: inherit; text-decoration: none; }
.card--link:hover {
  transform: translateY(-1px);
  box-shadow: var(--shadow-md);
  text-decoration: none;
}
.card--link {
  transition: transform var(--dur-2) var(--ease),
              box-shadow var(--dur-2) var(--ease);
}

/* Etiket over en værdi i en detaljeliste — "Model", "Periode", "Pris".
   Klassen hed .stat-label og blev brugt både til dette OG som KPI-etiket;
   nøgletallene hedder nu .stat__label, så denne er kun det ene. */
.stat-label { font-size: 12px; font-weight: 500; color: var(--text-body); }
/* .stat-value stod her indtil fase 8. Den var KPI-værdi nummer to ved siden
   af .stat__value; sidste bruger (reminders.php) er skrevet om. */

/* --- Knapper ------------------------------------------------------- */

.btn {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  padding: 9px 16px;
  border: 1px solid transparent;
  border-radius: var(--radius);
  background: var(--bg-surface);
  color: var(--text);
  font-size: 14px; font-weight: 500;
  cursor: pointer;
  /* Navngivne egenskaber, ikke "all": en uspecificeret transition rammer
     også bredde og polstring, og så hakker knapper der skifter tekst. */
  transition: background var(--dur-1) var(--ease),
              border-color var(--dur-1) var(--ease),
              color var(--dur-1) var(--ease);
  text-decoration: none;
  white-space: nowrap;
}
.btn:hover { text-decoration: none; }
.btn:disabled { opacity: .55; cursor: not-allowed; }

.btn--primary { background: var(--accent); color: var(--on-accent); }
.btn--primary:hover { background: var(--accent-hover); }

.btn--secondary { background: var(--bg-surface); color: var(--text); border-color: var(--border); }
.btn--secondary:hover { background: var(--bg-subtle); }

.btn--quiet { background: transparent; color: var(--text-muted); }
.btn--quiet:hover { background: var(--bg-subtle); color: var(--text); }

.btn--danger { background: var(--bg-surface); color: var(--danger); border-color: var(--border); }
.btn--danger:hover { border-color: var(--danger); background: var(--danger-soft); }

.btn--sm { padding: 6px 12px; font-size: 13px; }

/* --- Piller: ét system til badges og deltaer ------------------------ */

/* Der var tre næsten ens komponenter: .badge (status som ord), .kpi__pill
   (delta som tal) og .pill. Nu én geometri.

   .kpi__pill er FJERNET i fase 8 — den var et rent alias uden egen mening.
   .badge er derimod BEVARET og er ikke et alias: en statusbadge er et ord
   der siger hvad noget er, en delta-pille er et tal der siger hvor meget
   noget flyttede sig. De deler geometri, ikke betydning, og .badge står 30
   steder på tværs af filerne. At omdøbe dem alle ville koste 30 chancer for
   at glemme én — for at slette en linje.

   .chip og .report-mast__chip er IKKE med her og skal ikke lægges ind:
   .chip er en klikbar placeholder-nøgle i mono, .report-mast__chip er et
   dokumentstempel der skal printe. De ligner hinanden — de er ikke det
   samme, og det bør den næste ikke "rette". */
.pill, .badge {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  padding: 3px 10px;
  border-radius: var(--radius-pill);
  font-size: 12px; font-weight: 500;
  background: var(--bg-subtle); color: var(--text-body);
  white-space: nowrap;
}

/* Teksten står i den mørknede variant, ikke i fladefarven: 12px i --success
   på --success-soft giver kun 3,0:1. Ink-varianterne rammer over 4,5:1. */
.pill--danger,  .badge--danger  { background: var(--danger-soft);  color: var(--danger-ink); }
.pill--warn,    .badge--warn    { background: var(--warn-soft);    color: var(--warn-ink); }
.pill--success, .badge--success { background: var(--success-soft); color: var(--success-ink); }
.pill--accent,  .badge--accent  { background: var(--accent-soft);  color: var(--accent-ink); }
.pill--neutral                  { background: var(--bg-subtle);    color: var(--text-body); }

/* Talvarianterne. En delta er et tal og ikke et ord, så den vejer tungere
   og får tabular-nums — ellers står ↑ 8,1 % og ↑ 11,4 % ikke i flugt under
   hinanden. Fladefarven er den samme som ordvarianternes. */
.pill--up, .pill--down, .pill--flat {
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.pill--up   { background: var(--success-soft); color: var(--success-ink); }
.pill--down { background: var(--danger-soft);  color: var(--danger-ink); }
.pill--flat { background: var(--bg-subtle);    color: var(--text-body); }

/* Dæmpet tekst i en tabelcelle — fx en kolonne der ikke gælder for rækken */
.text-muted { color: var(--text-muted); }
/* Brødtekst i et kort. Standardfarven i et kort er --text; en forklarende
   afsnitstekst skal ligge et trin under sin egen overskrift. Fandtes indtil
   fase 8 kun som style="color: var(--text-body)" på et par dusin afsnit. */
.text-body { color: var(--text-body); }

/* --- Tabeller ------------------------------------------------------ */

/* position: relative er ikke pynt — den er det der holder siden inde på
   skærmen. .sr-only er position: absolute uden offsets, og uden en
   positioneret forfader bliver dens containing block hele dokumentet. Så
   klipper hverken .table-wrap's overflow eller .card--flush's overflow den:
   absolut positionerede kasser klippes kun af forfædre der ligger i deres
   EGEN containing block-kæde. En skjult etiket i en tabels yderste kolonne
   — "Slå søgeordet op", "Fjern siden" — lander derfor flere hundrede pixels
   ude til højre for kortet og gør hele dokumentet så bredt. Den er usynlig
   (clip: rect(0 0 0 0)), men tæller med i scroll-arealet, så resultatet er
   en side der kan scrolles vandret hen til ingenting.
   Med relative her bliver .table-wrap containing block, og etiketterne
   klippes af den scroll-ramme de i forvejen hører til.
   Rør ikke .row-menu-list: den er position: fixed, og fixed påvirkes ikke
   af en relativ forfader — kun af transform/filter/will-change. */
.table-wrap { overflow-x: auto; position: relative; }

.table {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
}
/* Mindre og tungere end cellerne under. Et tabelhoved i samme størrelse som
   sine data læses som endnu en datarække. */
.table th {
  padding: 12px 16px;
  border-bottom: 1px solid var(--border);
  font-size: 11px; font-weight: 600; color: var(--text-muted);
  letter-spacing: .04em;
  text-align: left;
  white-space: nowrap;
}
.table td {
  padding: 12px 16px;
  height: 44px;
  color: var(--text-body);
  border-bottom: 1px solid var(--border);
}

/* Tættere variant til detaljetabeller — de otte datasnit på sagssiden.
   Forskellen i tæthed er halvdelen af hierarkiet: en overskriftstabel og
   en detaljetabel må ikke veje det samme. */
.table--dense td { padding: 10px 14px; height: 40px; }
.table--dense th { padding: 10px 14px; }
.table tbody tr:nth-child(odd) { background: var(--bg-inset); }
/* Hover skal være mørkere end BEGGE zebra-bånd. --bg-subtle (#F5F5F4) er
   lysere end --bg-inset (#EFEEED), så hver anden række blev lysere af at
   blive peget på — og hover var i praksis usynlig på halvdelen af tabellen. */
.table tbody tr:hover { background: var(--bg-hover); }
/* .text-muted er (0,1,0) og .table td er (0,1,1) — utility-klassen tabte
   derfor tavst på hver celle der bar den. Fem steder skrev den allerede og
   fik ingen virkning. */
.table td.text-muted { color: var(--text-muted); }
.table .col-num { width: 48px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.table .num { text-align: right; font-variant-numeric: tabular-nums; }
/* Sparkline-kolonne. Fast bredde, ellers får kurven den plads der er tilbage
   og bliver enten en stribe eller halvdelen af tabellen. */
.table .cell-spark { width: 128px; }
.table .cell-spark .chart { min-width: 88px; }
/* Sumrække: skal læses som et facit, ikke som endnu en datarække */
.table tfoot td {
  border-bottom: 0;
  border-top: 1px solid var(--border);
  font-weight: 600;
  color: var(--text);
  background: var(--bg-inset);
}
.table tfoot .foot-label { color: var(--text-muted); font-weight: 500; }
.table a { text-decoration: none; }
.table a:hover { text-decoration: underline; }

/* Deltaer er brødtekst i en tabel — de skal kunne læses, ikke kun anes.
   --success på hvidt er 3,4:1; ink-varianten er 5,4:1. */
.delta-up   { color: var(--success-ink); }
.delta-down { color: var(--danger-ink); }

/* Kebab-menu i sidste kolonne */
.row-menu { position: relative; width: 44px; text-align: right; }
.row-menu-btn {
  background: none; border: 0; cursor: pointer;
  color: var(--text-muted); padding: 4px 8px; border-radius: var(--radius-sm);
  line-height: 1;
}
.row-menu-btn:hover { background: var(--bg-subtle); color: var(--text); }
/* Fixed, ikke absolute: menuen ville ellers ligge inde i .table-wrap's
   overflow-kontekst og enten blive klippet eller udløse en scrollbar.
   Koordinaterne sættes af JS ud fra knappens position. */
.row-menu-list {
  position: fixed;
  min-width: 170px;
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-pop);
  padding: var(--sp-1);
  list-style: none;
  z-index: 40;
}
.row-menu-list[hidden] { display: none; }
.row-menu-list a,
.row-menu-list button {
  display: flex; align-items: center; gap: var(--sp-2);
  width: 100%;
  padding: 8px 10px;
  background: none; border: 0;
  border-radius: var(--radius-sm);
  color: var(--text-body); font-size: 13px; text-align: left;
  cursor: pointer; text-decoration: none;
}
.row-menu-list a:hover,
.row-menu-list button:hover { background: var(--bg-subtle); text-decoration: none; }
.row-menu-list .is-danger { color: var(--danger); }

/* --- Formularer ---------------------------------------------------- */

.form-field { margin-bottom: var(--sp-4); }
.form-field label {
  display: block;
  margin-bottom: var(--sp-2);
  font-size: 13px; font-weight: 500; color: var(--text);
}
.form-field input[type=text],
.form-field input[type=email],
.form-field input[type=password],
.form-field input[type=number],
.form-field input[type=date],
.form-field select,
.form-field textarea {
  width: 100%;
  padding: 10px 12px;
  background: var(--bg-subtle);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font-size: 14px;
}
.form-field textarea { min-height: 110px; resize: vertical; line-height: 1.55; }
.form-field input:focus,
.form-field select:focus,
.form-field textarea:focus {
  background: var(--bg-surface);
  border-color: var(--accent);
  outline: none;
}
.form-hint { margin-top: var(--sp-2); font-size: 12px; color: var(--text-muted); }
.form-field.has-error input,
.form-field.has-error select,
.form-field.has-error textarea { border-color: var(--danger); }
.form-error { margin-top: var(--sp-2); font-size: 12px; color: var(--danger); }

.form-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--sp-4);
}
.form-check { display: flex; align-items: center; gap: var(--sp-2); }
.form-check input { width: 16px; height: 16px; accent-color: var(--accent); }
.form-check label { margin: 0; }

/* Afstands-hjælpere. Findes fordi alternativet var inline style="margin: …"
   på et halvt hundrede steder, og reglen i CLAUDE.md tillader kun inline
   style til beregnet geometri fra data. Skalaen er --sp-*, ikke frie tal, så
   de ikke kan bruges til at opfinde nye afstande. */
.sp-t-2 { margin-top: var(--sp-2); }
.sp-t-3 { margin-top: var(--sp-3); }
.sp-t-4 { margin-top: var(--sp-4); }
.sp-t-5 { margin-top: var(--sp-5); }
.sp-b-1 { margin-bottom: var(--sp-1); }
.sp-b-2 { margin-bottom: var(--sp-2); }
.sp-b-3 { margin-bottom: var(--sp-3); }
.sp-b-4 { margin-bottom: var(--sp-4); }
.sp-b-5 { margin-bottom: var(--sp-5); }
.sp-l-2 { margin-left: var(--sp-2); }

/* En formular der skal stå på linje med en knap ved siden af */
.form-inline { display: inline-block; }

.form-actions {
  display: flex; justify-content: flex-end; gap: var(--sp-2);
  margin-top: var(--sp-6);
  padding-top: var(--sp-5);
  border-top: 1px solid var(--border);
}

/* --- Flash --------------------------------------------------------- */

.flash {
  display: flex; align-items: flex-start; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  margin-bottom: var(--sp-4);
  border-radius: var(--radius);
  font-size: 14px;
}
.flash--success { background: var(--success-soft); color: var(--success); }
.flash--error   { background: var(--danger-soft);  color: var(--danger); }
.flash--warning { background: var(--warn-soft);    color: var(--warn); }
.flash--info    { background: var(--bg-subtle);    color: var(--text-body); }
.flash p { flex: 1; }
.flash-close { background: none; border: 0; cursor: pointer; color: inherit; opacity: .7; padding: 0; }
.flash-close:hover { opacity: 1; }

/* --- Grafer: klientlaget (assets/js/chart.js) ----------------------- */

/* Værten er en <figure> med data-chart. --chart-h sættes af JS ud fra
   data-height, så den tomme og den tynde tilstand fylder præcis det samme
   som kurven ville — ellers hopper layoutet den dag data kommer til. */
.chart { position: relative; display: block; margin: 0; }
.chart svg { display: block; overflow: visible; }

/* #clicks-chart var fase 4's selektor og stod her én udgivelse, så
   case_view.php ikke kunne knække halvvejs gennem en FTP-upload. Fjernet i
   fase 8 sammen med fallbacket i chart.js — ingen side skriver id'et mere. */

/* Indtegning. JS sætter stroke-dasharray og -dashoffset som SVG-attributter
   og nulstiller offset ved første synlighed; overgangen ligger her, så
   varigheden er et token og ikke et tal i JS. Ved reduceret bevægelse sætter
   JS aldrig offset — kurven står tegnet fra første frame. */
.chart__line--draw {
  transition: stroke-dashoffset var(--dur-chart) var(--ease-out);
}

.chart-empty {
  display: flex; align-items: center; justify-content: center;
  min-height: var(--chart-h, 160px);
  padding: var(--sp-4);
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius);
  color: var(--text-muted); font-size: 13px; text-align: center;
}

.chart-thin {
  display: flex; flex-direction: column; justify-content: center;
  gap: var(--sp-1);
  min-height: var(--chart-h, 160px);
}
/* Tallet er --fs-display i en fuld graf, men en sparkline er 40px høj, og
   34px tekst i en 40px kasse flyder ud over kanten. min() binder skriften
   til den erklærede højde uden at der skal findes to klasser. */
.chart-thin__value {
  font-size: min(var(--fs-display), calc(var(--chart-h, 160px) * .5));
  font-weight: 600;
  letter-spacing: -.02em; line-height: 1.1;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}
.chart-thin__note { font-size: 12px; color: var(--text-muted); }

/* Alt nul er ikke det samme som ingen data: grundlinjen bliver stående, og
   forklaringen lægger sig oven på den frem for at erstatte grafen. */
.chart-zero {
  position: absolute; left: 0; right: 0; top: 0; bottom: 0;
  display: grid; place-items: center;
  pointer-events: none;
  color: var(--text-muted); font-size: 12px;
}

.chart-tip {
  position: absolute; top: 0;
  padding: var(--sp-2) var(--sp-3);
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-pop);
  font-size: 12px; color: var(--text-body);
  white-space: nowrap;
  pointer-events: none;
}
.chart-tip[hidden] { display: none; }

/* --- Upload-zone --------------------------------------------------- */

.upload-zone {
  display: flex; flex-direction: column; align-items: center; gap: var(--sp-2);
  padding: var(--sp-10) var(--sp-5);
  background: var(--bg-subtle);
  border: 2px dashed var(--border-strong);
  border-radius: var(--radius-lg);
  text-align: center;
  cursor: pointer;
  transition: background var(--dur-2) var(--ease),
              border-color var(--dur-2) var(--ease);
}
.upload-zone .icon { color: var(--text-muted); }
/* Knappen er ren pynt — zonen fanger klikket, så filvælgeren kun åbnes én gang */
.upload-pick { pointer-events: none; margin: var(--sp-1) 0; }
.upload-zone:hover { border-color: var(--text-muted); }
.upload-zone.is-dragover {
  background: var(--accent-soft);
  border-color: var(--accent);
}
.upload-zone.is-dragover .icon,
.upload-zone.is-dragover .empty-text { color: var(--accent); }

.upload-files { list-style: none; margin-top: var(--sp-3); }
.upload-files li {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3);
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.upload-files .file-name { flex: 1; color: var(--text); font-size: 14px; word-break: break-all; }
.upload-files .file-size { color: var(--text-muted); font-size: 12px; white-space: nowrap; }

/* --- Tomme tilstande ----------------------------------------------- */

.empty {
  display: flex; flex-direction: column; align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-10) var(--sp-5);
  text-align: center;
}
.empty .icon { color: var(--text-faint); }
.empty-text { color: var(--text); font-size: 15px; }

/* --- Login --------------------------------------------------------- */

.login-page {
  min-height: 100vh;
  display: grid; place-items: center;
  padding: var(--sp-5);
}
.login-card { width: 100%; max-width: 380px; }
.login-card .card-title { margin-bottom: var(--sp-5); }
.login-card .btn { width: 100%; justify-content: center; }

/* --- Forside ------------------------------------------------------- */

.landing-card {
  width: 100%; max-width: 480px;
  text-align: center;
}
.landing-mark { color: var(--accent); margin-bottom: var(--sp-3); }
.landing-title { font-size: 26px; font-weight: 600; margin-bottom: var(--sp-3); }
.landing-text {
  color: var(--text-muted);
  font-size: 15px; line-height: 1.6;
  margin-bottom: var(--sp-5);
}
/* Uden login står teksten sidst — så skal afstanden til knappen ikke stå tilbage */
.landing-text:last-child { margin-bottom: 0; }
/* User-Agent-linjen er lang og må hellere brække end skubbe kortet ud på mobil */
.landing-text code {
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--text);
  background: var(--bg-inset);
  border-radius: var(--radius-sm);
  padding: 2px 6px;
  overflow-wrap: anywhere;
}

/* --- Responsivt ---------------------------------------------------- */

@media (max-width: 1100px) {
  .grid-2 { grid-template-columns: 1fr; }

  /* Seks spor: hero og tabel tager hele bredden, de fire små fliser står
     to og to. Under 1100px er 12 spor ikke længere en inddeling, det er
     bare tolv smalle striber. */
  .bento { grid-template-columns: repeat(6, minmax(0, 1fr)); }
  .bento__8, .bento__4 { grid-column: span 6; }
  .bento__3 { grid-column: span 3; }
}

@media (max-width: 768px) {
  .app { grid-template-columns: 1fr; }
  .app.is-collapsed { grid-template-columns: 1fr; }

  /* To spor: hver flise er enten hel eller halv. Bentoen er nu en liste
     med et par par i, ikke et layout. */
  .bento { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-4); }
  .bento__8, .bento__4 { grid-column: span 2; }
  .bento__3 { grid-column: span 1; }

  .sidebar {
    position: fixed; top: 0; left: 0; bottom: 0;
    width: var(--sidebar-w);
    z-index: 50;
    transform: translateX(-100%);
    transition: transform var(--dur-2) var(--ease);
  }
  .app.is-nav-open .sidebar { transform: translateX(0); }
  .sidebar-collapse { display: none; }

  /* Sammenfoldet tilstand hører til desktop. Uden denne nulstilling åbner
     mobilmenuen uden tekst — og fold-ud-knappen findes ikke her. */
  .app.is-collapsed .sidebar { padding-left: var(--sp-3); padding-right: var(--sp-3); }
  .app.is-collapsed .nav-label,
  .app.is-collapsed .nav-group-title span,
  .app.is-collapsed .sidebar-brand span { display: inline; }
  .app.is-collapsed .nav-link { justify-content: flex-start; padding: 10px 12px; }
  .app.is-collapsed .nav-group-title { justify-content: space-between; }

  .topbar .nav-toggle { display: inline-flex; }

  .content { padding: var(--sp-4); }
  .page-head { flex-direction: column; }
}

@media (max-width: 640px) {
  /* Én flise ad gangen. To halve fliser med et tal i hver er ikke en
     sammenligning på 600px, det er to tal der er blevet for små.
     ALLE spænd nulstilles til 1 / -1: med ét spor ville "span 2" fra
     768px-blokken tvinge et implicit spor nummer to frem, og rækken ville
     flyde ud over skærmkanten — samme fælde som .stat--hero ved 400px. */
  .bento { grid-template-columns: 1fr; }
  .bento__8, .bento__4, .bento__3 { grid-column: 1 / -1; }
}

/* prefers-reduced-motion stod her. Den er flyttet til filens allersidste
   linjer: alt med animation ELLER transition efter dette punkt var ikke
   dækket af den. Se hale-ordenen i banneret øverst. */

/* --- Filterrække i card-head --------------------------------------- */

.filter-bar {
  display: flex;
  align-items: flex-end;
  gap: var(--sp-2);
  flex-wrap: wrap;
}
.filter-bar select,
.filter-bar input[type=text] {
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-surface);
  font-size: 13px;
}
.filter-bar select:focus,
.filter-bar input:focus { outline: none; border-color: var(--accent); }
/* Et .form-field i filterrækken bærer sin egen etiket og skal opføre sig
   som en kolonne i rækken, ikke som et felt i en formular under hinanden.
   Stod indtil fase 8 som style="margin:0; flex:1 1 240px" på hvert felt. */
.filter-bar .form-field { margin: 0; flex: 1 1 240px; }

/* Et <select> der står alene uden for et .form-field. Native selects er kun
   så brede som deres længste option, og en modelliste med lange slugs ville
   sprænge kortet. box-sizing, fordi polstringen ellers lægger sig oven i de
   100 %. */
.select-block { display: block; width: 100%; max-width: 100%; box-sizing: border-box; }

.mono { font-family: var(--font-mono); font-size: 12px; }

/* --- Placeholder-chips --------------------------------------------- */

.chip-row { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-2); }

.chip {
  padding: 4px 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  background: var(--bg-subtle);
  color: var(--text-body);
  font-family: var(--font-mono);
  font-size: 11px;
  cursor: pointer;
}
.chip:hover { border-color: var(--accent); color: var(--accent); }
.chip.is-static { cursor: default; }
.chip.is-static:hover { border-color: var(--border); color: var(--text-body); }

/* --- Promptvisning -------------------------------------------------- */

.prompt-box {
  margin: var(--sp-2) 0 0;
  padding: var(--sp-4);
  max-height: 460px;
  overflow: auto;
  background: var(--bg-inset);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-family: var(--font-mono);
  font-size: 12px;
  line-height: 1.6;
  white-space: pre-wrap;
  word-break: break-word;
  color: var(--text-body);
}
.prompt-box[hidden] { display: none; }

/* Håndskrevet trin-for-trin-liste på en hjælpeside. Løsere linjeafstand end
   brødtekst, fordi hvert punkt er en handling man skal kunne finde tilbage
   til midt i at udføre den. Stod indtil fase 8 som inline style tre steder. */
.list-prose {
  padding-left: var(--sp-5);
  color: var(--text-body);
  line-height: 1.9;
}

/* --- Renderet AI-svar ----------------------------------------------- */

.md-body { color: var(--text-body); font-size: 14px; line-height: 1.65; }
.md-body > * + * { margin-top: var(--sp-3); }
.md-body h2 {
  margin-top: var(--sp-6);
  font-size: 16px;
  font-weight: 600;
  color: var(--text);
}
/* Modellens ## bliver til h3, fordi kortets egen titel er h2 */
.md-body h3 { margin-top: var(--sp-6); font-size: 15px; font-weight: 600; color: var(--text); }
.md-body h4 { margin-top: var(--sp-5); }
.md-body h4, .md-body h5, .md-body h6 { font-size: 13px; font-weight: 600; color: var(--text); }
.md-body > :first-child { margin-top: 0; }
.md-body ul, .md-body ol { padding-left: var(--sp-5); }
.md-body li + li { margin-top: var(--sp-1); }
.md-body strong { color: var(--text); font-weight: 600; }
.md-body code {
  padding: 1px 5px;
  background: var(--bg-inset);
  border-radius: var(--radius-sm);
  font-family: var(--font-mono);
  font-size: 12px;
}
.md-body blockquote {
  padding-left: var(--sp-4);
  border-left: 2px solid var(--border-strong);
  color: var(--text-muted);
}
.md-body hr { border: 0; border-top: 1px solid var(--border); }
.md-body .table-wrap { margin: var(--sp-4) 0; }
/* AI-svar laver nogle gange brede tabeller med en lang prosa-kolonne. Den
   kolonne wrapper til mange linjer, så rækken bliver høj — med default
   vertical-align: middle svæver de korte talceller så midt i luften. Top-
   justering og lidt luftigere linjer holder cellerne læselige uden at se
   oppustede ud; celler over ~28 tegn får ikke længere nowrap-pres. */
.md-body .table td { vertical-align: top; height: auto; line-height: 1.5; }

/* --- Testbænk: modelvalg og resultatkolonner ------------------------ */

.model-picker {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: var(--sp-3);
}

.model-option {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  padding: var(--sp-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.model-option:hover { border-color: var(--border-strong); }
.model-option input { margin-top: 3px; width: 16px; height: 16px; accent-color: var(--accent); }
.model-option input:disabled { cursor: not-allowed; }
.model-option input:disabled ~ span { opacity: .5; }
.model-option span { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.model-option strong { color: var(--text); font-weight: 600; font-size: 13px; }
.model-option .mono { word-break: break-all; }

.compare-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: var(--sp-5);
  margin-bottom: var(--sp-5);
}
.compare-grid[hidden] { display: none; }
.compare-grid > .card + .card { margin-top: 0; }

.card--compare { display: flex; flex-direction: column; }
.card--compare .md-body { flex: 1; max-height: 520px; overflow-y: auto; }
.card--compare .card-title { word-break: break-all; }

/* Sporene er PAR, ikke etiket og værdi. Hvert par pakkes i sit eget <div>, så
   etiketten står over værdien og to par deler en række — se system.php og
   reminders.php. En <dl> med bare dt/dd som børn falder ned i den samme
   opdeling, men uden parringen: så lander værdien midt i blokken, langt fra
   sin etiket. Det var fejlen i AI-forbrugskortet indtil fase 7c. */
.run-meta {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--sp-2) var(--sp-4);
  margin: var(--sp-4) 0;
  padding-top: var(--sp-3);
  border-top: 1px solid var(--border);
}
.run-meta dt { font-size: 12px; color: var(--text-muted); }
.run-meta dd { margin: 0; font-size: 13px; color: var(--text); font-variant-numeric: tabular-nums; }

/* --- Sortérbare tabelhoveder ---------------------------------------- */

.sort-link {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  color: inherit;
  white-space: nowrap;
}
.sort-link:hover { color: var(--text); text-decoration: none; }
.sort-link.is-active { color: var(--text); }
.table th .sort-link { font: inherit; }
.table th.num .sort-link { justify-content: flex-end; width: 100%; }

.sort-arrow { color: var(--accent); font-size: 11px; }

/* --- Filter-tællere ved korttitlen ----------------------------------- */

.filter-counts { display: flex; align-items: center; gap: var(--sp-4); flex-wrap: wrap; }

.filter-count {
  display: flex; align-items: baseline; gap: var(--sp-2);
  padding: 4px 8px;
  border-radius: var(--radius);
  color: inherit; text-decoration: none;
  transition: background var(--dur-1) var(--ease);
}
.filter-count:hover { background: var(--bg-subtle); text-decoration: none; }
.filter-count.is-active { background: var(--bg-subtle); }

.filter-count-num {
  font-size: 15px; font-weight: 600;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
/* Tallet er tekst, ikke en flade. Fladefarverne ligger på 3,0-3,5:1 på
   hvidt og er under gulvet — ink-varianterne er over. */
.filter-count-num.is-danger  { color: var(--danger-ink); }
.filter-count-num.is-warn    { color: var(--warn-ink); }
.filter-count-num.is-success { color: var(--success-ink); }

.filter-count-label { font-size: 12px; color: var(--text-muted); white-space: nowrap; }

/* Titel og statuslinks til venstre, tællerne til højre. Under 900px
   falder tællerne ned under titlen i stedet for at klemme den. */
.card-head--stack { flex-wrap: wrap; }
.card-head-main { display: flex; align-items: center; gap: var(--sp-4); flex-wrap: wrap; }

/* --- Rapportkalender (DESIGN.md §7.12) ------------------------------- */

.cal-nav { display: flex; align-items: center; gap: var(--sp-2); }
.cal-nav-btn {
  display: flex; align-items: center; justify-content: center;
  width: 26px; height: 26px;
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  transition: background var(--dur-1) var(--ease), color var(--dur-1) var(--ease);
}
.cal-nav-btn:hover { background: var(--bg-subtle); color: var(--text); text-decoration: none; }
.cal-month {
  font-size: 13px; font-weight: 500; color: var(--text);
  font-variant-numeric: tabular-nums;
  /* Bred nok til "September 2026", så chevronerne ikke flytter sig når
     man bladrer mellem måneder med forskellig navnelængde */
  min-width: 112px; text-align: center;
}

.cal-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 4px;
}

.cal-dow {
  font-size: 11px; color: var(--text-muted);
  text-align: center;
  padding-bottom: var(--sp-2);
}

.cal-day {
  display: flex; align-items: center; justify-content: center;
  aspect-ratio: 1;
  font-size: 13px;
  color: var(--text-body);
  border-radius: var(--radius-pill);
  font-variant-numeric: tabular-nums;
}
.cal-day--out { color: var(--text-faint); }

/* I dag markeres med en ring, så den kan ses sammen med de to andre
   tilstande i stedet for at konkurrere med dem om baggrunden. */
.cal-day--today { box-shadow: inset 0 0 0 1px var(--border-strong); }

.cal-day--upload { background: var(--accent-soft); color: var(--accent); font-weight: 500; }

/* Påmindelsen vinder over uploaden: en dag kan være begge dele, og
   den der endnu ikke er sket, er den man skal handle på. */
.cal-day--reminder { background: var(--accent); color: var(--on-accent); font-weight: 500; }

.cal-legend {
  display: flex; flex-wrap: wrap; gap: var(--sp-4);
  margin-top: var(--sp-4);
  list-style: none;
  font-size: 12px; color: var(--text-muted);
}
.cal-legend li { display: flex; align-items: center; gap: var(--sp-2); }
.cal-key { width: 12px; height: 12px; border-radius: var(--radius-pill); flex: none; }
.cal-key--upload   { background: var(--accent-soft); }
.cal-key--reminder { background: var(--accent); }

/* --- Store datasæt: sticky hoved, søgning og paginering -------------- */

/* Sorterings- og sidelinks peger på kortets id, så man bliver stående ved
   tabellen i stedet for at lande i toppen. Topbaren er sticky og ville
   ellers dække korthovedet når browseren springer dertil. */
.card[id] { scroll-margin-top: calc(var(--topbar-h) + var(--sp-4)); }

/* Tabellen scroller i sin egen ramme, ikke med siden. Ellers ville
   .table-wrap's vandrette overflow gøre det umuligt at gøre tabelhovedet
   sticky mod sidens scroll. */
.table-wrap--tall {
  max-height: calc(100vh - 300px);
  min-height: 320px;
  overflow: auto;
}

.table--sticky thead th {
  position: sticky; top: 0; z-index: 5;
  /* Sticky hoved skal have baggrund — ellers scroller rækkerne op igennem det */
  background: var(--bg-surface);
}
/* En kant på en sticky celle følger ikke med, så den tegnes som skygge */
.table--sticky thead th::after {
  content: '';
  position: absolute; left: 0; right: 0; bottom: -1px;
  border-bottom: 1px solid var(--border);
}

/* Nøglekolonnen kan være en lang URL. Den må bryde, men ikke skubbe
   taltallene ud af syne. */
.cell-key { max-width: 420px; word-break: break-word; }

/* Handlingsknapper yderst i en tabelrække — hent, slet og lignende */
.row-actions { display: flex; align-items: center; justify-content: flex-end; gap: var(--sp-2); }

/* Chips inde i en tabelcelle står alene og skal ikke have luft over sig */
.chip-row--tight { margin-top: 0; }
.chip-count { color: var(--text-muted); font-variant-numeric: tabular-nums; }

.table-search { display: flex; align-items: center; gap: var(--sp-2); }
.table-search input[type=search] {
  width: 220px;
  padding: 7px 12px;
  background: var(--bg-subtle);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font-size: 13px;
}
.table-search input[type=search]:focus {
  background: var(--bg-surface);
  border-color: var(--accent);
  outline: none;
}

.pager {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-4);
  padding: var(--sp-4) var(--sp-5);
  border-top: 1px solid var(--border);
}
.pager-status { font-size: 12px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.pager-links  { display: flex; align-items: center; gap: var(--sp-3); }
.pager-count  { font-size: 12px; color: var(--text-muted); white-space: nowrap; }

/* Yderpunkterne står som knapper der ikke kan trykkes, i stedet for at
   forsvinde — knapperne skal blive stående samme sted mens man bladrer. */
.btn.is-disabled {
  opacity: .45;
  pointer-events: none;
}

@media (max-width: 768px) {
  .table-wrap--tall { max-height: none; }
  .table-search input[type=search] { width: 100%; }
  .card--flush .card-head { flex-wrap: wrap; }
  .pager { flex-direction: column; align-items: flex-start; }
}

/* --- Indstillinger --------------------------------------------------- */

.settings-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--sp-4) var(--sp-5);
}
.settings-grid .form-field { margin-bottom: 0; }

/* Fluebenet står i en kolonne ved siden af inputfelter. Rækken får samme
   højde som et inputfelt (14px tekst + 10px polstring + 1px kant, top og
   bund), så flueben og felter står i samme linje — og teksten under dem
   begynder i samme højde. */
.settings-grid .form-check { min-height: 44px; }

/* Hvor værdien kommer fra: databasen eller config.php. Står småt, fordi det
   kun er interessant når man er i tvivl. */
.setting-origin {
  margin-top: var(--sp-2);
  font-size: 11px;
  color: var(--text-faint);
}

.link-btn {
  padding: 0;
  border: 0;
  background: none;
  color: var(--accent);
  font-size: 11px;
  cursor: pointer;
  text-decoration: underline;
}
.link-btn:hover { color: var(--accent-hover); }

/* --- Påmindelser: kvittering i udsendelsesloggen --------------------- */

/* Ankeret må ikke ende bag den klæbende topbar */
#udsendelser { scroll-margin-top: calc(var(--topbar-h) + var(--sp-4)); }

/* Rækker sendt inden for de sidste to minutter — det man lige har trykket på */
.table tbody tr.is-fresh,
.table tbody tr.is-fresh:nth-child(odd) { background: var(--accent-soft); }

/* --- Forhåndsvisning af påmindelsesmail ------------------------------ */

/* Mailen har sin egen inline styling og skal ikke arve appens. En sandboxed
   iframe holder de to stylesheets adskilt. */
.mail-preview {
  display: block;
  width: 100%;
  height: 560px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-inset);
}

/* --- Arbejdsnoter (fase 6) ------------------------------------------- */

/* Ankeret må ikke ende bag den klæbende topbar */
#arbejdsnoter, #top { scroll-margin-top: calc(var(--topbar-h) + var(--sp-4)); }

/* Tilføj-note: foldet sammen bag en discret knap */
.note-add { margin-bottom: var(--sp-4); }
.note-add > summary {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  cursor: pointer; list-style: none;
  padding: 6px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-subtle);
  color: var(--text-body); font-size: 13px; font-weight: 500;
  width: fit-content;
}
.note-add > summary::-webkit-details-marker { display: none; }
.note-add > summary:hover { border-color: var(--border-strong); color: var(--text); }
.note-add[open] > summary { margin-bottom: var(--sp-3); }
.note-add-body { padding-top: var(--sp-1); }

/* Note-formular: kompakt, felterne på én linje under teksten */
.note-form textarea { min-height: 60px; }
.note-form-row {
  display: flex; align-items: center; gap: var(--sp-2);
  flex-wrap: wrap; margin-top: var(--sp-2);
}
.note-form-row select,
.note-form-row input[type="date"] {
  width: auto;
  padding: 8px 12px;
  background: var(--bg-subtle);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font-size: 13px;
  color: var(--text-body);
}
/* Chevronen tegnes af wrapperen, ikke af et data-URI-ikon inde i feltet.
   Den gamle løsning havde en hardkodet #888 gemt som %23888 inde i en
   url() — usynlig for enhver farveændring, og 2,5px stregtykkelse hvor
   resten af ikonerne har 1,5. En <select> kan ikke have ::after selv. */
.select-wrap { position: relative; display: inline-flex; }
.select-wrap::after {
  content: "";
  position: absolute; right: 13px; top: 50%;
  width: 7px; height: 7px; margin-top: -5px;
  border-right: 1.5px solid var(--text-muted);
  border-bottom: 1.5px solid var(--text-muted);
  transform: rotate(45deg);
  pointer-events: none;
}
.note-form-row select {
  appearance: none; -webkit-appearance: none;
  padding-right: 32px;
  cursor: pointer;
}
.note-form-row select:hover { border-color: var(--text-muted); }
.note-form-row select:focus,
.note-form-row input[type="date"]:focus {
  background-color: var(--bg-surface);
  border-color: var(--accent);
  outline: none;
}
.note-form-check {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  font-size: 13px; color: var(--text-body); white-space: nowrap;
}
.note-form-check input { width: 16px; height: 16px; accent-color: var(--accent); }

/* Liste af noter */
.note-group-label {
  display: flex; align-items: center; gap: var(--sp-1);
  font-size: 12px; font-weight: 600; text-transform: uppercase;
  letter-spacing: .03em; color: var(--text-muted);
  margin: var(--sp-4) 0 var(--sp-2);
}
.note-list { display: flex; flex-direction: column; gap: var(--sp-3); }
.note-list--page { padding: var(--sp-5); }

.note-item {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: var(--sp-3) var(--sp-4);
  background: var(--bg-card);
}
.note-item--task { background: var(--warn-soft); border-color: var(--warn-soft); }
.note-item-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-2); margin-bottom: var(--sp-2);
}
.note-item-date { font-size: 12px; color: var(--text-muted); white-space: nowrap; }
.note-item-body { font-size: 13px; }
.note-item-body > :first-child { margin-top: 0; }

.note-item-meta {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-2);
  margin-top: var(--sp-2); padding-top: var(--sp-2);
  border-top: 1px solid var(--border);
  font-size: 12px;
}
.note-item-meta a { display: inline-flex; align-items: center; gap: 2px; }
.note-sep { color: var(--border-strong); }
.note-inline-form { display: inline; }
.note-link-btn {
  display: inline-flex; align-items: center; gap: 2px;
  padding: 0; border: 0; background: none; cursor: pointer;
  color: var(--text-muted); font-size: 12px;
}
.note-link-btn:hover { color: var(--text); }
.note-link-btn--danger:hover { color: var(--danger); }
.note-edit-panel {
  margin-top: var(--sp-3); padding-top: var(--sp-3);
  border-top: 1px dashed var(--border);
}

.notes-search {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: 6px 10px; background: var(--bg-subtle);
  border: 1px solid var(--border); border-radius: var(--radius);
  color: var(--text-muted); max-width: 260px;
}
.notes-search input { border: 0; background: none; padding: 0; width: 100%; }
.notes-search input:focus { outline: none; }

/* --- Tidslinje ------------------------------------------------------- */

.timeline { list-style: none; margin: 0; padding: 0; }
.timeline-item {
  position: relative; display: flex; gap: var(--sp-3);
  padding: 0 0 var(--sp-4) var(--sp-4);
}
.timeline-item::before {
  content: ""; position: absolute; left: 4px; top: 6px; bottom: -2px;
  width: 1px; background: var(--border);
}
.timeline-item:last-child { padding-bottom: 0; }
.timeline-item:last-child::before { display: none; }
.timeline-dot {
  position: absolute; left: 0; top: 5px;
  width: 9px; height: 9px; border-radius: var(--radius-pill);
  background: var(--border-strong);
}
.timeline-item--note .timeline-dot { background: var(--accent); }
.timeline-item--report .timeline-dot { background: var(--text-muted); }
/* Analysekørsler kom med i fase 7c. --series-2 og ikke --success: prikken
   siger HVAD der skete, ikke om det gik godt — status står i sin egen badge,
   og en grøn prik på en fejlet kørsel ville modsige den. */
.timeline-item--analysis .timeline-dot { background: var(--series-2); }
.timeline-body { flex: 1; min-width: 0; }
.timeline-head { display: flex; align-items: center; gap: var(--sp-2); margin-bottom: 2px; }
.timeline-date { font-size: 12px; color: var(--text-muted); }
.timeline-text { font-size: 13px; color: var(--text-body); margin: 0; }

/* --- Styleguide: kun styleguide.php bruger disse -------------------- */

/* Siden er værktøj, ikke produkt. Reglerne herunder må aldrig bruges
   uden for styleguide.php — bliver de det, er komponenten ikke færdig. */

.sg-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: var(--sp-4);
}
.sg-swatch {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--bg-surface);
}
/* Farven kommer ind som en custom property fra PHP (--sg-c), ikke som en
   inline background. Samme princip som rapportens beregnede søjlebredder:
   markup'en leverer en VÆRDI, stylesheetet bestemmer hvad der gøres med den. */
.sg-swatch__chip {
  height: 54px;
  background: var(--sg-c, var(--bg-inset));
  border-bottom: 1px solid var(--border);
}
.sg-swatch__body { padding: var(--sp-2) var(--sp-3); }
.sg-swatch__name {
  font-family: var(--font-mono); font-size: 11.5px; color: var(--text);
  overflow-wrap: anywhere;
}
.sg-swatch__val,
.sg-swatch__ratio {
  font-family: var(--font-mono); font-size: 11px; color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.sg-swatch__ratio.is-pass { color: var(--success-ink); }
.sg-swatch__ratio.is-fail { color: var(--danger-ink); }

/* Prøverække: hvad komponenten hedder til venstre, komponenten til højre */
.sg-row {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: var(--sp-3) var(--sp-4);
  padding: var(--sp-3) 0;
}
.sg-row + .sg-row { border-top: 1px solid var(--border); }
.sg-row__key {
  flex: none; width: 190px;
  font-family: var(--font-mono); font-size: 11.5px; color: var(--text-muted);
}
.sg-row__demo { display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-3); }

/* Højdestigen vises på sidefarven, ellers kan man ikke se skyggen */
.sg-elev {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: var(--sp-5);
  padding: var(--sp-6);
  background: var(--bg-page);
  border-radius: var(--radius);
}
.sg-elev__box {
  padding: var(--sp-4);
  background: var(--bg-surface);
  border-radius: var(--radius);
  font-size: 12px; color: var(--text-muted);
}
.sg-elev__box b { display: block; color: var(--text); font-size: 13px; }
.sg-elev__box--0 { box-shadow: none; border: 1px solid var(--border); }
.sg-elev__box--1 { box-shadow: var(--shadow-sm); }
.sg-elev__box--2 { box-shadow: var(--shadow-md); }
.sg-elev__box--3 { box-shadow: var(--shadow-lg); }

/* Advarselsbjælke øverst på siden når ?empty=1 er sat */
.sg-note {
  padding: var(--sp-3) var(--sp-4);
  background: var(--accent-soft);
  border-radius: var(--radius);
  font-size: 13px; color: var(--accent-ink);
  margin-bottom: var(--sp-5);
}
.sg-note code { font-family: var(--font-mono); }

/* Live-aflæsning af brugerens bevægelsesindstilling */
.sg-motion { font-size: 13px; color: var(--text-body); }
.sg-motion b { color: var(--text); }

/* Dataviz-sektionen: hver primitiv i flere tilstande ved siden af hinanden.
   Fast minimumsbredde, så en tegning der klapper sammen, gør det synligt. */
.sg-viz {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: var(--sp-5);
  flex: 1 1 100%;
  align-items: start;
}
.sg-viz__case { min-width: 0; }
.sg-viz__label {
  font-family: var(--font-mono); font-size: 11px;
  color: var(--text-muted);
  margin-bottom: var(--sp-2);
}
/* En primitiv der med rette returnerer tom streng, skal kunne SES at gøre det
   — ellers ligner en tom firkant en fejl. */
.sg-viz__none {
  padding: var(--sp-3);
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-sm);
  font-size: 12px; color: var(--text-muted);
}

/* Sparklines skal have en bredde at tegne i. I en flex-række bliver en tom
   <figure> nul bred, og grafen ville være usynlig frem for forkert. */
.sg-spark {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: var(--sp-5);
  flex: 1 1 100%;
  align-items: center;
}

/* Småting siden selv har brug for, så den ikke skal bruge inline style */
.sg-foot       { margin-top: var(--sp-4); }
.sg-flush      { margin-bottom: 0; }
.sg-prose      { max-width: 58ch; }
.sg-table-auto { width: auto; }
.sg-card-demo  { width: 240px; }

/* =====================================================================
   Kunderapporten — report_pdf.php og public_report.php.

   Rapporten er et dokument, ikke en skærmflade: et ark med masthead,
   nummererede afsnit, målte tal og en metodenote til sidst. Tallene står
   med monospace og tabulære cifre, så kolonner flugter lodret og et
   femcifret tal ikke skubber rækken skæv.

   Tonefarver sættes af en tone-*-klasse på wrapperen; tegningerne arver
   farven via currentColor, så der ikke skal en variant af hver graf til.
   ===================================================================== */

.tone-good { color: var(--success-ink); }
.tone-bad  { color: var(--danger-ink); }
.tone-warn { color: var(--warn-ink); }
.tone-flat { color: var(--text-body); }
.tone-ink  { color: var(--text-body); }   /* neutral datafarve — søjler uden dom */

.report-page { background: var(--bg-page); }

/* Værktøjslinje — kun på skærm, ryger væk ved print. Egen baggrund, ellers
   løber arket op under den når man scroller. */
/* flex-wrap er ikke pynt: arbejdsarkets værktøjslinje har to link-knapper, en
   hint og en hentknap, og uden ombrydning løber de ud over skærmkanten på en
   telefon og tager hele sidens vandrette scroll med sig. */
.report-toolbar {
  position: sticky; top: 0; z-index: 10;
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-3);
  max-width: 960px; margin: 0 auto; padding: var(--sp-3) var(--sp-4);
  background: var(--bg-page);
  border-bottom: 1px solid var(--border);
}
.report-toolbar__spacer { flex: 1; }
.report-toolbar__hint {
  margin: 0;
  font-family: var(--font-mono); font-size: 12px; color: var(--text-body);
}

/* Selve arket — bliver til A4-fladen ved print */
.report-sheet {
  --plot-h: 200px;                      /* kurvens højde; skrues ned på små skærme */
  max-width: 960px; margin: 0 auto var(--sp-10);
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  padding: var(--sp-10) var(--sp-8);
  color: var(--text-body);
}

/* --- Masthead: hvem, hvad, hvornår, hvorfra ----------------------- */

.report-mast {
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--sp-6) var(--sp-8); align-items: start;
  padding-bottom: var(--sp-5);
  border-bottom: 2px solid var(--text);
}
.report-mast__agency {
  margin: 0 0 var(--sp-3);
  font-family: var(--font-mono); font-size: 11px; font-weight: 600;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--accent);
}
.report-mast__title {
  margin: 0 0 var(--sp-2);
  font-size: 30px; line-height: 1.1; font-weight: 600;
  letter-spacing: -0.02em; color: var(--text); text-wrap: balance;
}
.report-mast__case { margin: 0; font-size: 15px; color: var(--text-body); }
.report-mast__case strong { color: var(--text); font-weight: 600; }
.report-mast__sep { margin: 0 8px; color: var(--text-faint); }
.report-mast__chip {
  display: inline-block; margin: var(--sp-3) 0 0; padding: 3px 10px;
  font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.04em;
  color: var(--text-body); background: var(--bg-subtle);
  border: 1px solid var(--border); border-radius: var(--radius-sm);
}

/* Dokumentets datablok. Mono og faste kolonner — det er her rapporten
   siger "det her er målt", ikke "det her er lavet i et tekstprogram". */
.report-meta { display: grid; gap: 5px; margin: 0; }
.report-meta__row { display: grid; grid-template-columns: 92px minmax(0, 1fr); gap: var(--sp-3); }
.report-meta__key {
  font-family: var(--font-mono); font-size: 10.5px; line-height: 1.5;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-body);
}
.report-meta__val {
  margin: 0;
  font-family: var(--font-mono); font-size: 12px; line-height: 1.35;
  font-variant-numeric: tabular-nums; color: var(--text);
}

/* --- Statusbånd: rapportens hovedkonklusion ----------------------- */

.report-status {
  display: grid; grid-template-columns: auto minmax(0, 1fr);
  gap: var(--sp-5); align-items: center;
  margin-top: var(--sp-6); padding: var(--sp-5) var(--sp-6);
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--bg-subtle);
}
.report-status.tone-good { background: var(--success-soft); border-color: var(--success); }
.report-status.tone-bad  { background: var(--danger-soft);  border-color: var(--danger); }

.report-status__flag {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  margin: 0; padding-right: var(--sp-5);
  border-right: 1px solid var(--border-strong);
}
.report-status__glyph { font-size: 18px; line-height: 1; }
.report-status__code {
  font-family: var(--font-mono); font-size: 11px; font-weight: 600;
  letter-spacing: 0.1em; text-transform: uppercase;
}
.report-status__title { margin: 0 0 var(--sp-1); font-size: 19px; font-weight: 600; color: var(--text); }
.report-status__text  { margin: 0; font-size: 14px; line-height: 1.55; color: var(--text-body); max-width: 68ch; }

/* --- Afsnit ------------------------------------------------------- */

.report-block { margin-top: var(--sp-10); }

.report-section__head {
  display: grid; grid-template-columns: 32px minmax(0, 1fr); align-items: baseline;
  padding-bottom: var(--sp-2); border-bottom: 1px solid var(--border-strong);
}
.report-section__no {
  font-family: var(--font-mono); font-size: 12px; font-weight: 600;
  letter-spacing: 0.04em; color: var(--accent);
}
.report-section__title {
  margin: 0; font-size: 17px; font-weight: 600; letter-spacing: -0.01em;
  color: var(--text); text-wrap: balance;
}
.report-section__lead {
  margin: var(--sp-3) 0 var(--sp-4) 32px;
  font-size: 13px; line-height: 1.55; color: var(--text-body);
  max-width: 74ch; text-wrap: pretty;
}
.report-caption {
  margin: var(--sp-3) 0 0;
  font-size: 12px; line-height: 1.5; color: var(--text-body); max-width: 74ch;
}
.report-note {
  margin: 0; padding: var(--sp-4) var(--sp-5);
  font-size: 13.5px; line-height: 1.55; color: var(--text-body);
  background: var(--bg-subtle); border: 1px solid var(--border); border-radius: var(--radius);
}

/* --- Nøgletal ------------------------------------------------------ */

.report-kpi-grid {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--sp-4); margin-top: var(--sp-4);
}
.report-kpi-grid--pair { grid-template-columns: repeat(2, minmax(0, 1fr)); }

.report-kpi {
  display: flex; flex-direction: column;
  padding: var(--sp-4);
  border: 1px solid var(--border); border-radius: var(--radius);
}
/* Fast højde til to linjer label: ellers står tallene i de fire fliser ikke
   på samme linje, når kun én af overskrifterne ombrydes. */
.report-kpi__head {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-2);
  min-height: 34px; margin-bottom: var(--sp-2);
}
.report-kpi__label { margin: 0; font-size: 12.5px; font-weight: 600; color: var(--text); }
.report-kpi__value {
  margin: 0 0 var(--sp-2);
  font: 600 30px/1 var(--font-mono);
  font-variant-numeric: tabular-nums; letter-spacing: -0.03em; color: var(--text);
}
.report-kpi__prev {
  margin: var(--sp-3) 0 0;
  font-family: var(--font-mono); font-size: 11px; font-variant-numeric: tabular-nums;
  color: var(--text-body);
}
.report-kpi__prev b { font-weight: 600; color: var(--text); }
.report-kpi__prev-none { color: var(--text-body); }
.report-kpi__help {
  margin: var(--sp-3) 0 0; padding-top: var(--sp-3);
  border-top: 1px solid var(--border);
  font-size: 12px; line-height: 1.5; color: var(--text-body);
}

/* De to små nøgletal under de to store — kun kundens ark. Klikrate og
   placering er stadig med, men de er ikke svaret på "går det frem": det er
   klik. Fire lige store fliser sagde at de fire tal vejede lige meget. */
.report-subkpi {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sp-4); margin-top: var(--sp-4);
  padding-top: var(--sp-4); border-top: 1px solid var(--border);
}
.report-subkpi__line {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 8px; margin: 0;
}
.report-subkpi__label { font-size: 12.5px; font-weight: 600; color: var(--text); }
.report-subkpi__value {
  font-family: var(--font-mono); font-size: 16px; font-weight: 600;
  font-variant-numeric: tabular-nums; letter-spacing: -0.02em; color: var(--text);
}
.report-subkpi__delta {
  font-family: var(--font-mono); font-size: 12px; font-variant-numeric: tabular-nums;
}
.report-subkpi__help {
  margin: var(--sp-1) 0 0;
  font-size: 12px; line-height: 1.5; color: var(--text-body);
}

/* Ændringslinjen: pil, tal, procent, ord — altid i den rækkefølge */
.report-delta {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 8px; margin: 0;
  font-family: var(--font-mono); font-size: 12.5px; font-variant-numeric: tabular-nums;
}
.report-delta__arrow { font-size: 10px; }
.report-delta__value { font-weight: 600; }
.report-delta__pct   { color: var(--text-body); }
.report-delta__text  { color: var(--text-body); font-family: var(--font); font-size: 12px; }

/* --- Målerskinne: samme tegning under alle nøgletal ---------------- */

.report-rail { margin-top: var(--sp-4); }
.report-rail__track {
  position: relative; height: 8px;
  background: var(--data-track); border-radius: var(--radius-xs);
}
.report-rail__fill {
  position: absolute; inset: 0 auto 0 0;
  background: currentColor; border-radius: var(--radius-xs);
}
.report-rail__dot {
  position: absolute; top: 50%; width: 11px; height: 11px; margin-left: -5.5px;
  background: currentColor; border: 2px solid var(--bg-surface); border-radius: 50%;
  transform: translateY(-50%);
}
/* Forrige periodes niveau — en streg der stikker op gennem skinnen */
.report-rail__prev {
  position: absolute; top: -3px; bottom: -3px; width: 2px; margin-left: -1px;
  background: var(--text); border-radius: 1px;
}
.report-rail__scale {
  display: flex; justify-content: space-between; margin-top: 5px;
  font-family: var(--font-mono); font-size: 10.5px; font-variant-numeric: tabular-nums;
  color: var(--text-body);
}

/* --- Rangerede rækker (top-lister, movers, benchmark, muligheder) -- */

.report-ranklist { margin-top: var(--sp-3); }

.report-row {
  display: grid;
  grid-template-columns: 28px minmax(0, 1fr) 104px 96px;
  grid-template-areas:
    "idx label bar value"
    "idx meta  meta meta";
  align-items: center; column-gap: var(--sp-3); row-gap: 2px;
  padding: var(--sp-2) 0;
}
.report-row + .report-row { border-top: 1px solid var(--border); }
.report-row__idx {
  grid-area: idx; align-self: center;
  font-family: var(--font-mono); font-size: 11px; font-variant-numeric: tabular-nums;
  color: var(--text-body);
}
.report-row__label {
  grid-area: label; min-width: 0;
  font-size: 13px; color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.report-row__bar {
  grid-area: bar; height: 8px; overflow: hidden;
  background: var(--data-track); border-radius: var(--radius-xs);
}
.report-row__fill {
  display: block; height: 100%;
  background: currentColor; border-radius: var(--radius-xs);
}
.report-row__value {
  grid-area: value; text-align: right;
  font-family: var(--font-mono); font-size: 12px; font-weight: 600;
  font-variant-numeric: tabular-nums; color: var(--text); white-space: nowrap;
}
.report-row__meta {
  grid-area: meta; min-width: 0;
  font-family: var(--font-mono); font-size: 10.5px; font-variant-numeric: tabular-nums;
  color: var(--text-body);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.report-row__meta:empty { display: none; }

/* To kolonner: fremgange mod fald */
.report-movers__cols { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-6); margin-top: var(--sp-3); }
.report-movers__head {
  margin: 0 0 var(--sp-2); padding-bottom: var(--sp-2);
  border-bottom: 1px solid var(--border);
  font-family: var(--font-mono); font-size: 11px; font-weight: 600;
  letter-spacing: 0.08em; text-transform: uppercase;
}
.report-movers__empty { margin: 0; font-size: 13px; color: var(--text-body); }

/* --- Diagrammer ---------------------------------------------------- */

.report-chart {
  margin-top: var(--sp-4); padding: var(--sp-5);
  border: 1px solid var(--border); border-radius: var(--radius);
}

/* Kurven: y-akse og x-akse står som HTML uden om SVG'en, så teksten ikke
   skaleres ned sammen med tegningen på en smal skærm. */
.report-plot {
  display: grid;
  grid-template-columns: 46px minmax(0, 1fr);
  grid-template-areas: "y area" ".  x";
  column-gap: var(--sp-2);
}
/* Fallback på --plot-h, fordi variablen kun er deklareret på .report-sheet.
   Kaldte man report_trend_chart() fra en app-side, kollapsede grafen til nul
   højde — den fejl lå gemt indtil primitiverne blev delt ud i fase 4. */
.report-plot__y {
  grid-area: y; position: relative; height: var(--plot-h, 200px);
  font-family: var(--font-mono); font-size: 10.5px; font-variant-numeric: tabular-nums;
  color: var(--text-body);
}
.report-plot__y span {
  position: absolute; right: 0; transform: translateY(-50%);
  line-height: 1;
}
.report-plot__area-wrap {
  grid-area: area; height: var(--plot-h, 200px);
  border-left: 1px solid var(--border-strong);
  border-bottom: 1px solid var(--border-strong);
}
.report-plot__svg { display: block; width: 100%; height: 100%; }
.report-plot__grid { stroke: var(--border); stroke-width: 1; }
.report-plot__area { fill: var(--accent-fill); stroke: none; }
.report-plot__mean { stroke: var(--text-faint); stroke-width: 1.5; stroke-dasharray: 5 4; }
.report-plot__line {
  stroke: var(--accent); stroke-width: 2;
  stroke-linejoin: round; stroke-linecap: round;
}
.report-plot__peak { fill: var(--bg-surface); stroke: var(--accent); stroke-width: 2; }
.report-plot__x {
  grid-area: x; display: flex; justify-content: space-between; padding-top: 6px;
  font-family: var(--font-mono); font-size: 10.5px; font-variant-numeric: tabular-nums;
  color: var(--text-body);
}

/* Aflæsningsstribe under kurven */
.report-facts {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--sp-4); margin: var(--sp-5) 0 0;
  padding-top: var(--sp-4); border-top: 1px solid var(--border);
}
.report-facts dt {
  font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--text-body);
}
.report-facts dd {
  margin: 3px 0 0;
  font: 600 15px/1.2 var(--font-mono); font-variant-numeric: tabular-nums;
  color: var(--text);
}

/* Søjler: positionsfordelingen */
/* Ingen mellemrum mellem kolonnerne: søjlerne holdes fra hinanden af
   polstring inde i hver plotflade, så nullinjen bliver én ubrudt streg
   i stedet for fem stumper. */
.report-cols {
  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr);
  align-items: end;
}
.report-cols__item { display: flex; flex-direction: column; align-items: center; gap: 4px; min-width: 0; }
.report-cols__val {
  font: 600 13px/1 var(--font-mono); font-variant-numeric: tabular-nums; color: var(--text);
}
.report-cols__plot {
  display: flex; align-items: flex-end; justify-content: center;
  width: 100%; height: 130px; padding: 0 6px;
  border-bottom: 1px solid var(--border-strong);
}
.report-cols__bar {
  width: 100%; max-width: 54px; min-height: 2px;
  background: currentColor;
  border-radius: var(--radius-xs) var(--radius-xs) 0 0;
}
.report-cols__lab {
  font-family: var(--font-mono); font-size: 11px; color: var(--text);
  white-space: nowrap;
}
.report-cols__pct {
  font-family: var(--font-mono); font-size: 10.5px; color: var(--text-body);
}

/* Delt søjle: brand mod ikke-brand */
.report-split { margin-top: var(--sp-4); }
.report-split__bar {
  display: flex; height: 14px; overflow: hidden;
  border-radius: 3px; background: var(--bg-inset);
}
.report-split__seg { display: block; height: 100%; }
.report-split__seg--new   { background: var(--accent); }
.report-split__seg--brand { background: var(--border-strong); }
.report-split__keys {
  display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-6); margin-top: var(--sp-3);
}
.report-split__key {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 12.5px; color: var(--text-body);
}
.report-split__key b {
  font-family: var(--font-mono); font-size: 12.5px; font-variant-numeric: tabular-nums;
  color: var(--text);
}
.report-split__swatch { width: 10px; height: 10px; border-radius: 2px; }

/* --- Vurderingen fra konsulenten ----------------------------------- */

.report-analysis__cards {
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-4); margin-top: var(--sp-4);
}
.report-analysis__card {
  padding: var(--sp-5);
  background: var(--bg-subtle);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.report-analysis__card-title { font-size: 15px; font-weight: 600; color: var(--text); margin: 0 0 var(--sp-2); }
.report-analysis__body { font-size: 13.5px; line-height: 1.6; color: var(--text-body); }
.report-analysis__card .table-wrap { overflow-x: auto; }
/* Kort med en tabel må gerne fylde begge kolonner */
.report-analysis__card:has(.table-wrap) { grid-column: 1 / -1; }

/* --- Metodenote ----------------------------------------------------- */

.report-method {
  margin-top: var(--sp-10); padding: var(--sp-5) var(--sp-6);
  background: var(--bg-subtle); border: 1px solid var(--border); border-radius: var(--radius);
}
.report-method__title {
  margin: 0 0 var(--sp-4);
  font-family: var(--font-mono); font-size: 11px; font-weight: 600;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--text);
}
.report-method__list { display: grid; gap: var(--sp-3); margin: 0; }
.report-method__list > div { display: grid; grid-template-columns: 130px minmax(0, 1fr); gap: var(--sp-4); }
.report-method__list dt {
  font-family: var(--font-mono); font-size: 11px; line-height: 1.6;
  letter-spacing: 0.04em; color: var(--text);
}
.report-method__list dd {
  margin: 0; font-size: 12.5px; line-height: 1.6; color: var(--text-body); max-width: 74ch;
}

.report-foot {
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: var(--sp-2);
  margin-top: var(--sp-8); padding-top: var(--sp-3);
  border-top: 2px solid var(--text);
  font-family: var(--font-mono); font-size: 11px; color: var(--text-body);
}
.report-foot__name { font-weight: 600; color: var(--text); letter-spacing: 0.04em; }

/* --- Responsivt: strukturen skifter, skriftstørrelserne står fast --- */

@media (max-width: 900px) {
  .report-sheet { padding: var(--sp-8) var(--sp-6); }
  .report-mast { grid-template-columns: minmax(0, 1fr); }
  .report-kpi-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .report-movers__cols { grid-template-columns: 1fr; gap: var(--sp-5); }
  .report-analysis__cards { grid-template-columns: 1fr; }
  .report-facts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 560px) {
  /* Arket går ud til kanten på en telefon. Rammen og de runde hjørner kostede
     ~34 px læsebredde for at tegne et papir ingen kan se kanten af alligevel. */
  .report-sheet {
    --plot-h: 150px;
    padding: var(--sp-6) var(--sp-4);
    border-left: 0; border-right: 0; border-radius: 0;
    box-shadow: none;
  }
  .report-mast__title { font-size: 24px; }

  /* Etiketkolonnen holdt ikke: "DATAGRUNDLAG" i mono-versaler er bredere end
     84 px, så nøglen brød om og værdien stod og flød. Nøgle over værdi i
     stedet — det er to linjer, men de er hele. */
  .report-meta__row { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .report-meta__val { overflow-wrap: anywhere; }

  .report-toolbar { padding: var(--sp-2) var(--sp-3); }
  /* Hintet handler om printdialogen. Den findes ikke på en telefon, og linjen
     skubber knapperne ned på en fjerde række. */
  .report-toolbar__hint { display: none; }

  .report-status { grid-template-columns: minmax(0, 1fr); gap: var(--sp-3); padding: var(--sp-4); }
  .report-status__flag {
    flex-direction: row; padding-right: 0; padding-bottom: var(--sp-3);
    border-right: none; border-bottom: 1px solid var(--border-strong);
    justify-content: flex-start;
  }

  .report-kpi-grid, .report-kpi-grid--pair { grid-template-columns: minmax(0, 1fr); }
  /* Flugtningshøjden findes kun for at holde fire tal på samme linje. Med én
     flise pr. række er den tom luft over hvert tal. */
  .report-kpi__head { min-height: 0; }
  .report-subkpi { grid-template-columns: minmax(0, 1fr); gap: var(--sp-3); }
  .report-section__lead { margin-left: 0; }

  /* Rækkerne bliver tre linjer: navn+tal, søjle, detaljer */
  .report-row {
    grid-template-columns: 24px minmax(0, 1fr) auto;
    grid-template-areas:
      "idx label value"
      "idx bar   bar"
      "idx meta  meta";
    row-gap: 4px;
  }
  .report-row__idx { align-self: start; }
  /* På en bred skærm er "…" en pæn afkortning af en lang URL, fordi resten af
     rækken stadig står. På en telefon er der ikke resten af en række: klippes
     labelen og meta-linjen dér, er søgeordet og placeringen væk, og så er
     rækken en søjle uden navn. Begge ombryder i stedet. */
  .report-row__label {
    white-space: normal; overflow: visible; text-overflow: clip;
    overflow-wrap: anywhere; line-height: 1.35;
  }
  .report-row__meta {
    white-space: normal; overflow: visible; text-overflow: clip;
    line-height: 1.45;
  }

  .report-plot { grid-template-columns: 38px minmax(0, 1fr); }
  .report-cols__plot { height: 96px; padding: 0 3px; }
  .report-cols__lab, .report-cols__pct { font-size: 10px; }
  .report-method { padding: var(--sp-4); }
  .report-method__list > div { grid-template-columns: minmax(0, 1fr); gap: 2px; }

  /* AI-svarets tabeller: sidepolstringen fra app-tabellerne er sat til en
     skærm der er bredere end telefonen. Smallere celler holder tabellen inde
     i kortet i stedet for at sende den ud i sin egen vandrette scroll. */
  .report-analysis__card { padding: var(--sp-4); }
  .report-analysis__card .table { font-size: 12.5px; }
  .report-analysis__card .table th,
  .report-analysis__card .table td { padding: 8px 10px; }
}

/* --- Hentelog: én linje pr. måned i backfill ----------------------- */

.backfill-log {
  list-style: none;
  margin: var(--sp-3) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.backfill-log[hidden] { display: none; }
.backfill-log li {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-2);
  font-size: 13px;
}
.backfill-log .backfill-month { color: var(--text-body); }

/* Statuslinjen er tom indtil en kørsel starter. Uden dette står der et
   tomt afsnits højde og skubber hjælpeteksten ned uden grund. */
.scan-status:empty { display: none; }

/* Nedtællingen og de to knapper efter en kørsel. Egen linje frem for at
   hænge efter statusteksten: to knapper midt i en sætning bliver til noget
   man læser i stedet for noget man trykker på. */
.scan-reload {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-2);
  margin-top: var(--sp-2);
}

/* Liste uden punkttegn inde i en tabelcelle. Bruges til PageSpeed-forslagene,
   hvor to-tre linjer skal stå under hinanden uden at cellen ligner en liste
   i et dokument. */
.plain-list { list-style: none; margin: 0; padding: 0; }
.plain-list li + li { margin-top: 2px; }

/* =====================================================================
   Sagsoverblik — case_view.php

   Sagens styringsinformation (status, hentemetode, åbne opgaver, forbrug,
   kontakt) lå før spredt i højre kolonne under otte tabeller. Den samles nu
   i ét bånd øverst på siden.

   Cellerne i båndet adskilles af 1px grid-gap på en farvet flade i stedet
   for kanter: så bliver stregerne hårfine både lodret og vandret, også når
   cellerne ombrydes til flere rækker.
   ===================================================================== */

/* Skyggen sidder på wrapperen — altså UDEN for dens egen overflow: hidden,
   som hårlinje-teknikken i .case-fact er afhængig af. Rør ikke ved
   overflow eller ved cellernes negative margener. */
.case-bar {
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  margin-bottom: var(--sp-5);
  box-shadow: var(--shadow-sm);
}

.case-bar__top {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: var(--sp-2) var(--sp-4);
  padding: var(--sp-3) var(--sp-5);
  background: var(--bg-sidebar);
  border-bottom: 1px solid var(--border);
}
.case-bar__period { font-size: 13px; color: var(--text-body); }
.case-bar__period strong { color: var(--text); font-weight: 600; }
.case-bar__tags { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }

/* Hårfine skillelinjer: hver celle tegner sin egen venstre- og topstreg og
   trækkes 1px op og til venstre, så nabostregerne lægger sig oven i hinanden
   og bliver til én. Yderkanterne havner under .case-bar's egen ramme og
   klippes af dens overflow. Modsat gap-på-farvet-flade efterlader det ikke
   grå huller, når sidste række er kortere end de andre. */
.case-bar__facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  margin: 0;
  background: var(--bg-surface);
}

.case-fact {
  display: flex; flex-direction: column; gap: var(--sp-2);
  margin: -1px 0 0 -1px;
  padding: var(--sp-4) var(--sp-5);
  background: var(--bg-surface);
  border-top: 1px solid var(--border);
  border-left: 1px solid var(--border);
}
.case-fact__label { font-size: 12px; font-weight: 500; color: var(--text-body); }
.case-fact__body  { margin: 0; display: flex; flex-direction: column; gap: var(--sp-1); min-width: 0; }
.case-fact__value {
  font-size: 17px; font-weight: 600; color: var(--text);
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}
.case-fact__meta  { font-size: 12px; color: var(--text-body); overflow-wrap: anywhere; }
.case-fact__extra { margin-top: var(--sp-1); }
/* --accent er 3,5:1 på hvidt og 3,0:1 på de bløde statusflader — for lidt til
   et 12px link. Ink-varianten holder over 4,5:1 begge steder. */
.case-fact a { color: var(--accent-ink); }

/* Tilstand får en hel flade, ikke bare en tekstfarve. Teksten i cellen siger
   det samme som farven, så beskeden aldrig ligger i farven alene. */
.case-fact--good { background: var(--success-soft); }
.case-fact--warn { background: var(--warn-soft); }
.case-fact--bad  { background: var(--danger-soft); }
.case-fact--good .case-fact__value { color: var(--success-ink); }
.case-fact--warn .case-fact__value { color: var(--warn-ink); }
.case-fact--bad  .case-fact__value { color: var(--danger-ink); }
/* Grå tekst på en tonet flade ser vasket ud — labels og meta går til --text */
.case-fact--good .case-fact__label, .case-fact--good .case-fact__meta,
.case-fact--warn .case-fact__label, .case-fact--warn .case-fact__meta,
.case-fact--bad  .case-fact__label, .case-fact--bad  .case-fact__meta { color: var(--text); }

.case-bar__note {
  padding: var(--sp-4) var(--sp-5);
  background: var(--bg-subtle);
  border-top: 1px solid var(--border);
}
.case-bar__note-text {
  margin-top: var(--sp-1);
  font-size: 13px; color: var(--text-body);
  white-space: pre-wrap; max-width: 72ch;
}

/* --- Nøgletal ------------------------------------------------------- */

/* Blokken hedder .stat og er GLOBAL — den bruges også af dashboardet og af
   påmindelsessiden. Den står her fordi den voksede her, og fordi at flytte
   regler på tværs af de tre stablede stylesheets er ren risiko uden gevinst.

   Samme stregprincip som sagsbåndet: fem tal i ÉN ramme frem for fem kort,
   så rækken læses som ét måleinstrument og ikke som fem beskeder.

   Aliaserne .kpi, .kpi__label, .kpi__value, .kpi__trend og .kpi__note er
   fjernet i fase 8. Ingen PHP-fil skrev dem længere. */
.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(168px, 1fr));
  margin-bottom: var(--sp-5);
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  /* Som .case-bar: skyggen på rammen, ikke på cellerne. Tilføj aldrig gap
     her — cellerne tegner selv stregerne med -1px margen. */
  box-shadow: var(--shadow-sm);
}
/* Samme stregteknik som sagsbåndet — se kommentaren ved .case-bar__facts */
.stat {
  display: flex; flex-direction: column;
  margin: -1px 0 0 -1px;
  padding: var(--sp-4) var(--sp-5);
  background: var(--bg-surface);
  border-top: 1px solid var(--border);
  border-left: 1px solid var(--border);
}
.stat__label {
  font-size: 12px; font-weight: 500;
  letter-spacing: .01em;
  color: var(--text-muted);
}
.stat__value {
  margin-top: var(--sp-2);
  font-size: 28px; font-weight: 600; line-height: 1.15;
  letter-spacing: -0.02em; color: var(--text);
  font-variant-numeric: tabular-nums;
}
.stat__trend {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-2);
  margin-top: auto; padding-top: var(--sp-3);
}
.stat__note { font-size: 12px; color: var(--text-muted); }

/* Plads til en sparkline mellem tal og delta. Højden er fast, så en celle
   uden graf står lige så høj som en med — ellers rykker rækken. */
.stat__spark { margin-top: var(--sp-2); height: 34px; }

/* Ét tal pr. skærm er svaret; resten er kontekst. Hero'en spænder to spor,
   så den ikke bare er større men også bredere end sine naboer. */
.stat--hero { grid-column: span 2; }
.stat--hero .stat__value {
  font-size: var(--fs-hero);
  letter-spacing: -0.03em;
}
.stat--hero .stat__spark { height: 56px; }

/* Til fliser der kun bærer et tal — fx en dato eller en optælling uden delta */
.stat--compact .stat__value { font-size: 20px; letter-spacing: -0.01em; }

/* En flise der ER et link — sagssidens håndtag. Hele fladen er klikmålet;
   et "se dem"-link i hjørnet ville gøre målet 60px bredt.
   Kun baggrunden bevæger sig: en transform her ville løfte cellen ud af
   hårlinje-rammen den deler med sine naboer, og rækken ville knække. */
a.stat {
  text-decoration: none;
  color: inherit;
  transition: background-color var(--dur-1) var(--ease);
}
a.stat:hover { background: var(--bg-hover); text-decoration: none; }
a.stat:hover .stat__value { color: var(--accent-ink); }
/* Noten er flisens eneste synlige tegn på at der er et sted at gå hen —
   uden den ligner en klikbar flise en flise. --accent-ink og ikke --accent:
   3,5:1 er for lidt til 12px tekst. */
a.stat .stat__note { color: var(--accent-ink); }
/* Tastaturfokus skal kunne ses uden for cellen, og cellerne overlapper
   hinanden med -1px — uden z-index klippes ringen af naboen. */
a.stat:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; position: relative; z-index: 1; }

/* En .stat der står ALENE i sit eget kort — dashboardets hero. Uden denne
   tegner blokken sine hårlinjer midt inde i kortet, og -1px-margenen der får
   nabostreger til at falde sammen i et grid, trækker indholdet skævt.
   grid-column nulstilles med: hero'en spænder to spor i et grid, men i et
   kort er der ingen spor at spænde. */
.stat--bare {
  margin: 0; padding: 0;
  border: 0; background: none;
  grid-column: auto;
}

/* Tonet celle. Teksten siger altid det samme som farven, og etiket og note
   går til --text: grå tekst på en farvet flade ser vasket ud. */
.stat--good { background: var(--success-soft); }
.stat--warn { background: var(--warn-soft); }
.stat--bad  { background: var(--danger-soft); }
.stat--good .stat__value { color: var(--success-ink); }
.stat--warn .stat__value { color: var(--warn-ink); }
.stat--bad  .stat__value { color: var(--danger-ink); }
.stat--good .stat__label, .stat--good .stat__note,
.stat--warn .stat__label, .stat--warn .stat__note,
.stat--bad  .stat__label, .stat--bad  .stat__note { color: var(--text); }

/* Variant med luft mellem fliserne i stedet for hårlinjer. Erstatter
   .grid-stats. Her ER gap rigtigt — cellerne er selvstændige kort og
   tegner ikke stregerne selv, så den fælles ramme findes ikke. */
.stat-grid--cards {
  background: none;
  border: 0;
  border-radius: 0;
  overflow: visible;
  box-shadow: none;
  gap: var(--sp-4);
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
.stat-grid--cards .stat {
  margin: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}

/* --- Sektionsoverskrift mellem kortgrupper -------------------------- */

/* Otte tabeller i træk er en liste uden inddeling. Overskriften deler dem i
   "hvad flytter sig", "muligheder" og "data" uden at gemme noget bag faner. */
.section-head {
  display: flex; align-items: baseline; justify-content: space-between;
  flex-wrap: wrap; gap: var(--sp-3);
  margin: var(--sp-6) 0 var(--sp-3);
  padding-bottom: var(--sp-2);
  border-bottom: 1px solid var(--border-strong);
}
.section-head:first-child { margin-top: 0; }
/* Den er sidens h2 og læste mindre end en korttitel, altså mindre end sine
   egne børn. */
.section-head__title { font-size: 15px; font-weight: 600; color: var(--text); }
.section-head__hint  { font-size: 12px; color: var(--text-body); }

/* --- Sagens to spalter ---------------------------------------------- */

.case-cols {
  display: grid;
  grid-template-columns: 2fr 1fr;
  gap: var(--sp-5);
  align-items: start;
  /* Falder sammen med .stat-grid's bundmargen; står alene efter et kort */
  margin-top: var(--sp-5);
}
.case-cols > * { min-width: 0; }

/* --- Sidekort: etiket/værdi-lister og underafsnit -------------------- */

.field-list { display: grid; gap: var(--sp-4); margin: 0; }
.field-list dt { margin-bottom: var(--sp-1); font-size: 12px; font-weight: 500; color: var(--text-body); }
.field-list dd { margin: 0; font-size: 14px; color: var(--text); }
.field-list dd .form-hint { margin-top: var(--sp-1); }
.field-list .mono { display: block; word-break: break-all; }

.card-section {
  margin-top: var(--sp-5);
  padding-top: var(--sp-4);
  border-top: 1px solid var(--border);
}
.card-section__title { margin-bottom: var(--sp-2); font-size: 13px; font-weight: 600; color: var(--text); }

.card-foot-note {
  margin-top: var(--sp-4);
  padding-top: var(--sp-3);
  border-top: 1px solid var(--border);
}

/* .run-meta bærer selv en topkant; inde i et kort lige under korthovedet
   ville den blive den anden streg på fire pixels. */
.run-meta--flush { margin-top: 0; padding-top: 0; border-top: 0; }

/* Indhold i et .card--flush har ingen polstring at arve — disse to giver
   den tilbage til de blokke der ikke er tabeller. */
.card-pad   { padding: var(--sp-3) var(--sp-5) 0; }
.card-pad-b { padding: var(--sp-3) var(--sp-5); }

/* --- Responsivt ----------------------------------------------------- */

@media (max-width: 1100px) {
  .case-cols { grid-template-columns: 1fr; }
  /* Højre spalte teleporterede før op over hele hovedspalten her (order: -1),
     fordi styringen ellers endte under otte tabeller. Den begrundelse gælder
     ikke længere: styringen står i sagsbåndet øverst, og siden har nu en
     rækkefølge — sådan går det, hvad kan der skrues på, grundlag. En spalte
     der bytter plads ved 1100px giver to forskellige sider at lære, og den
     ene af dem begynder midt i en sektion. */
}

@media (max-width: 768px) {
  .topbar { padding: 0 var(--sp-4); gap: var(--sp-2); }
  .page-actions { flex-wrap: wrap; }
}

@media (max-width: 640px) {
  .case-bar__top, .case-bar__note, .case-fact,
  .stat { padding: var(--sp-3) var(--sp-4); }
  /* To faste spalter slår auto-fit her: 190px-minimum ville give tre smalle
     celler på en 600px skærm. */
  .case-bar__facts, .stat-grid { grid-template-columns: 1fr 1fr; }
  .stat__value { font-size: 22px; }
  /* Hero'en spænder stadig to spor, altså hele bredden — men den skal ikke
     også være 44px når resten er 22. */
  .stat--hero .stat__value { font-size: 30px; }
  /* Sparkline-slotten skifter IKKE højde her. Grafen tegnes i den højde der
     står i data-height, og en slot der er lavere end tegningen ville lade
     kurven lægge sig oven i delta-pillen. To tal for den samme højde driver
     fra hinanden; det ene tal står i markup'en, hvor JS kan læse det. */

  .card { padding: var(--sp-4); }
  .card--flush .card-head { padding: var(--sp-4) var(--sp-4) var(--sp-3); }
  .card-pad   { padding: var(--sp-3) var(--sp-4) 0; }
  .card-pad-b { padding: var(--sp-3) var(--sp-4); }
  .table th, .table td { padding: 10px 12px; }
  .cell-key { max-width: 220px; }

  .page-actions { width: 100%; }
  .page-actions .btn { flex: 1 1 auto; justify-content: center; }
}

@media (max-width: 400px) {
  .case-bar__facts, .stat-grid { grid-template-columns: 1fr; }
  /* Med ét spor ville "span 2" tvinge et implicit spor nummer to frem, og
     så flyder rækken ud over skærmkanten. */
  .stat--hero { grid-column: auto; }
}

/* =====================================================================
   Dataviz — de delte tegneprimitiver uden for kunderapporten.
   inc/dataviz.php. Fjerde sektion i hale-ordenen: efter sagsoverblikket,
   før print.

   Reglerne herunder rører IKKE en eneste .report-*-regel. De justerer
   primitiverne INDE i en .dv, så det samme opkald kan tegne både en
   dokumentsektion og en flise i et kort. Ændrer man en .report-*-regel for
   at få en app-flise til at passe, ændrer man samtidig kunderapporten —
   og den er det eneste kundevendte output i systemet.
   ===================================================================== */

.dv {
  /* Rapportarket sætter 200px. Et kort har ikke den plads. */
  --plot-h: 160px;
}
.dv__title {
  font-size: 12px; font-weight: 500;
  letter-spacing: .01em;
  color: var(--text-muted);
  margin-bottom: var(--sp-3);
}
.dv__note {
  font-size: 12px; color: var(--text-muted);
  margin-top: var(--sp-3);
}

/* Tættere mål end i dokumentet: en flise har ikke en A4-bredde at tage af */
.dv .report-cols__plot { height: 84px; }
.dv .report-row { grid-template-columns: 24px minmax(0, 1fr) 88px 72px; }
.dv .report-row__value,
.dv .report-row__meta { font-size: 11.5px; }
.dv .report-ranklist { margin-top: 0; }
.dv .report-rail { margin-top: var(--sp-3); }

/* Rapportens billedtekster forklarer dokumentet. Et kort har sin egen
   undertekst i .dv__note, og to forklaringer under samme tegning er én
   for meget. dv_posband() klipper sin egen af; denne fanger resten. */
.dv .report-caption { display: none; }

/* --- Stablet søjle: en bestand fordelt på tilstande ------------------ */

/* Samme mål som .report-split__bar, så en delt og en stablet søjle vejer det
   samme på en side hvor begge står. Segmenterne bærer statusfarver og ikke
   seriefarver: hvert segment ER en tilstand, ikke en mængde. */
.dv-stack__bar {
  display: flex; height: 10px; overflow: hidden;
  background: var(--data-track);
  border-radius: var(--radius-xs);
}
.dv-stack__seg { display: block; height: 100%; }
.dv-stack__seg--bad  { background: var(--danger); }
.dv-stack__seg--warn { background: var(--warn); }
.dv-stack__seg--good { background: var(--success); }
.dv-stack__seg--ink  { background: var(--data-ink); }

.dv-stack__keys {
  display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-4);
  margin-top: var(--sp-3);
  font-size: 12px; color: var(--text-body);
}
.dv-stack__key { display: flex; align-items: center; gap: var(--sp-2); }
.dv-stack__key b {
  font-weight: 600; color: var(--text);
  font-variant-numeric: tabular-nums;
}
.dv-stack__swatch {
  width: 10px; height: 10px; flex: none;
  border-radius: var(--radius-xs);
}

/* --- Ringen: den ene primitiv rapporten aldrig fik ------------------- */

.dv-ring {
  position: relative;
  aspect-ratio: 1;
  display: grid; place-items: center;
  flex: none;
}
.dv-ring svg { display: block; width: 100%; height: 100%; }
.dv-ring__track {
  stroke: var(--data-track);
  stroke-width: 5;
}
/* Ingen indtegning her. Bevægelse på server-tegninger kræver at de renderes
   på nul og får deres rigtige værdi en frame efter — og det ville ændre
   kunderapportens første frame. Rapporten er det eneste kundevendte output,
   og fase 4's hele pointe er at den ikke må ændre sig. */
.dv-ring__fill {
  stroke: currentColor;
  stroke-width: 5;
  stroke-linecap: round;
}
.dv-ring__center {
  position: absolute;
  font-size: 13px; font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--text);
  line-height: 1;
}

/* --- Tonefarver på en tegning --------------------------------------- */

/* .tone-* findes i forvejen i rapportlaget og bruges her uændret.
   Serieklasserne er nye og bærer MÆNGDE, ikke dom — en klikkurve er ikke
   god eller dårlig, den er stor eller lille. */
.dv-s1 { color: var(--series-1); }
.dv-s2 { color: var(--series-2); }
.dv-s3 { color: var(--series-3); }
.dv-s4 { color: var(--series-4); }
.dv-s5 { color: var(--series-5); }

/* --- Mikro-søjle i en taltabel -------------------------------------- */

/* Femoghalvtreds rækker med fem talkolonner er læsbare én række ad gangen og
   ulæselige som helhed: man kan ikke se hvor faldet ligger uden at læse hver
   linje. Søjlen ligger under tallet i samme celle og er skaleret til den
   største værdi PÅ SIDEN, så formen kan ses uden at tallet mistes.

   Søjlen bærer MÆNGDE, ikke dom — derfor seriefarver og aldrig statusfarver.
   Den findes kun på tælle-kolonner: klik og eksponeringer har et nulpunkt og
   en top. Placering og klikrate har ingen af delene, og en søjle på dem ville
   påstå en skala der ikke findes.

   Højden er gratis. Cellens polstring trækkes fra det søjlen lægger til, så
   rækken bliver på sine 44px — ellers ville tabellen vokse 14 % af en
   tegning der skal koste ingenting. */
.table td.cell-bar { padding-top: 8px; padding-bottom: 8px; }
.cell-bar__wrap { position: relative; display: block; padding-bottom: 7px; }
.cell-bar__track {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 3px;
  display: flex; justify-content: flex-end;
  background: var(--data-track);
  border-radius: var(--radius-xs);
}
/* currentColor, så farven kommer fra .dv-s1/.dv-s2 på sporet og
   seriepaletten kun står ét sted */
.cell-bar__fill {
  height: 100%;
  border-radius: var(--radius-xs);
  background: currentColor;
}

/* --- Print: arket bliver til PDF'en ------------------------------- */
@media print {
  @page { margin: 14mm; }

  .no-print, .report-toolbar { display: none !important; }
  .report-page { background: var(--bg-surface); }

  /* Skygger er skærmdybde. På papir bliver de til grå udtværinger langs
     hver kant, så alt der har fået højde, mister den igen ved print. */
  .card, .case-bar, .stat-grid, .report-sheet {
    box-shadow: none !important;
  }

  /* Uden dette printer browseren søjler og udfyldninger som hvidt papir,
     og hele rapporten mister sine tegninger. Klientgraferne har samme
     problem: en kurve uden sin flade er en tom kasse på papir. */
  .report-sheet, .report-sheet *,
  .chart, .chart *,
  .cell-bar__track, .cell-bar__fill {
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }

  /* Tooltippet hører til musen og findes ikke på papir */
  .chart-tip { display: none !important; }

  .report-sheet {
    max-width: none; margin: 0; padding: 0;
    border: none; border-radius: 0; box-shadow: none;
  }

  /* Rækker, fliser og diagrammer må ikke knækkes midt over af et sideskift.
     .report-movers__col og .report-subkpi__item stod her og matchede intet —
     klassenavnene er .report-movers__cols (flertal) og .report-subkpi__line. */
  .report-status, .report-kpi, .report-row, .report-chart, .report-plot,
  .report-facts, .report-cols, .report-split, .report-analysis__card,
  .report-method__list > div, .report-movers__cols,
  .report-subkpi__line { break-inside: avoid; }

  /* En overskrift alene nederst på en side er værre end et tidligt sideskift */
  .report-section__head, .report-section__lead, .report-movers__head,
  .report-analysis__card-title, .report-method__title { break-after: avoid; }

  .report-block { break-before: auto; }
  .report-method { break-inside: avoid; }
}

/* --- Reduceret bevægelse: SKAL være filens sidste blok -------------- */

/* Denne blok dækker kun det der står FØR den. Læg aldrig nye regler under.
   animation-iteration-count er nødvendig, fordi en løkke ellers kører
   videre i .01ms-trin i stedet for at stoppe; scroll-behavior fanger et
   fremtidigt "smooth" som varigheder ikke rører. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}
