/* Bifrost – stiler.

   Fargene kommer fra themes.css. Her ligger form, rom og rytme.

   Tre valg som går igjen:

   1. Én radius-skala og én skyggeskala. Alt som er «et kort» ser likt ut,
      uansett hvilken side det står på.
   2. Tall settes med tabulære siffer. Et beløp som endrer seg skal ikke
      flytte på teksten rundt.
   3. Ingenting er bare farge. Status har ikon eller form ved siden av
      fargen, slik at det også leses i gråtoner og av fargeblinde. */

:root {
  --r-sm: 8px;
  --r-md: 12px;
  --r-lg: 16px;
  --r-xl: 22px;
  --r-pill: 999px;
  --topbar-h: 60px;
  --page-w: 1120px;
  --ease: cubic-bezier(.32, .72, 0, 1);
}

* { box-sizing: border-box; margin: 0; padding: 0; }

html { -webkit-text-size-adjust: 100%; }
html, body { height: 100%; }

body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, Roboto,
               "Helvetica Neue", Arial, sans-serif;
  font-size: 15px;
  line-height: 1.5;
  background: var(--bg);
  color: var(--text);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  transition: background .35s var(--ease), color .35s var(--ease);
}

body::before {
  content: "";
  position: fixed;
  inset: 0;
  background: var(--bg-glow);
  pointer-events: none;
  z-index: 0;
}

#app { position: relative; z-index: 1; min-height: 100%; display: flex; flex-direction: column; }

a { color: var(--accent); text-decoration: none; }
button { font: inherit; color: inherit; cursor: pointer; background: none; border: none; }
svg.ico { flex: none; display: block; }

h1, h2, h3, h4 { line-height: 1.25; letter-spacing: -.011em; font-weight: 650; }
h1 { font-size: 1.5rem; }
h2 { font-size: 1.05rem; }
h3 { font-size: .97rem; }
h4 { font-size: .9rem; }

.num { font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; }
.muted { color: var(--muted); }
.faint { color: var(--faint); }
.center { text-align: center; }
.mono {
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  font-size: .86em;
}
.stack { display: flex; flex-direction: column; gap: 10px; }
.row { display: flex; align-items: center; gap: 10px; }
.row.wrap { flex-wrap: wrap; }
.spread { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.grow { flex: 1; min-width: 0; }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Fokus skal alltid være synlig, men bare når man faktisk bruker tastatur. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}

/* ============================ Toppmeny ============================ */

.topbar {
  position: sticky; top: 0; z-index: 30;
  /* Som installert app (viewport-fit=cover + gjennomsiktig statuslinje)
     tegnes siden under klokka og batteriindikatoren — bufferen skyver
     innholdet i toplinjen ned forbi dem. I en vanlig nettleser er
     env(safe-area-inset-top) 0 og ingenting endres. */
  height: calc(var(--topbar-h) + env(safe-area-inset-top, 0px));
  display: flex; align-items: center; gap: 14px;
  padding: env(safe-area-inset-top, 0px) clamp(14px, 3vw, 26px) 0;
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  backdrop-filter: saturate(180%) blur(14px);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
  border-bottom: 1px solid var(--border);
}

.brand {
  display: flex; align-items: center; gap: 9px;
  color: var(--text); font-weight: 680; font-size: 1.02rem;
  letter-spacing: -.01em; flex: none;
}
.brand .mark {
  width: 32px; height: 32px; border-radius: 10px;
  display: grid; place-items: center;
  background: var(--accent-soft); color: var(--accent);
}
.brand:hover .mark { background: var(--accent); color: var(--accent-contrast); }
.brand .mark, .brand .mark svg { transition: background .18s, color .18s; }

/* Hovednavigasjon — bare på bred skjerm; på telefon ligger den nederst */
.topnav { display: flex; align-items: center; gap: 2px; margin-left: 10px; }
.topnav a {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 7px 12px; border-radius: var(--r-md);
  color: var(--muted); font-size: .88rem; font-weight: 550;
  transition: background .15s, color .15s;
}
.topnav a:hover { background: var(--surface-2); color: var(--text); }
.topnav a.on { background: var(--accent-soft); color: var(--accent); }

.topbar-right { margin-left: auto; display: flex; align-items: center; gap: 8px; }

.iconbtn {
  width: 36px; height: 36px; border-radius: var(--r-md);
  display: grid; place-items: center;
  color: var(--muted);
  transition: background .15s, color .15s;
}
.iconbtn:hover { background: var(--surface-2); color: var(--text); }
.iconbtn.on { background: var(--accent-soft); color: var(--accent); }

/* Segmentert bryter — brukes til nett/lokalt */
.segmented {
  display: inline-flex; align-items: center; gap: 2px;
  padding: 3px; border-radius: var(--r-pill);
  background: var(--surface-inset); border: 1px solid var(--border);
}
.segmented button {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 11px; border-radius: var(--r-pill);
  font-size: .8rem; font-weight: 600; color: var(--muted);
  transition: background .18s var(--ease), color .18s;
}
.segmented button:hover { color: var(--text); }
.segmented button.on {
  background: var(--surface); color: var(--text);
  box-shadow: var(--shadow);
}
.segmented button.on.warnish { color: var(--warn); }
.segmented button.on.jobbish { color: var(--accent); }

/* Jobbmodus i toppmenyen: ordmerket bytter til selskapsnavnet, og merket
   får aksentfargen så det ses at hele portalen har byttet ham — ikke bare
   bakgrunnen. */
.topbar.jobb .brand .mark { background: var(--accent); color: var(--accent-contrast); }

/* Temaskiftet inn og ut av jobbmodus skal gli, ikke klippe. Klassen legges
   på <html> i et halvsekund rundt byttet (se settJobbmodus i app.js), så
   fargene dimmer over i stedet for å hoppe — og er borte igjen før den kan
   gjøre vanlige sidebytter seige. */
.tema-glid, .tema-glid *, .tema-glid *::before, .tema-glid *::after {
  transition: background-color .5s ease, background .5s ease,
              border-color .5s ease, color .5s ease, box-shadow .5s ease;
}

/* Oppdateringsmerket. Finnes bare når det faktisk ligger noe nytt — en
   permanent «alt er som det skal»-indikator er bare støy. */
.update-chip {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 6px 12px; border-radius: var(--r-pill);
  background: var(--warn-soft); color: var(--warn);
  font-size: .82rem; font-weight: 620;
  border: 1px solid transparent;
  transition: filter .15s, border-color .15s;
}
.update-chip:hover { filter: brightness(1.08); border-color: currentColor; }
/* Rødt når en tjeneste har stanset. Samme form som oppdateringsmerket — det
   er samme slags beskjed, bare mer alvorlig. */
.update-chip.bad { background: var(--danger-soft); color: var(--danger); }
.update-chip.bad .cnt { background: var(--danger); }
.update-chip .cnt {
  min-width: 18px; height: 18px; padding: 0 5px; border-radius: var(--r-pill);
  display: inline-grid; place-items: center;
  background: var(--warn); color: var(--bg);
  font-size: .72rem; font-weight: 700;
}

/* Brukermeny */
.usermenu { position: relative; }
.usermenu > button {
  display: flex; align-items: center; gap: 8px;
  padding: 4px 9px 4px 4px; border-radius: var(--r-pill);
  border: 1px solid transparent;
}
.usermenu > button:hover { border-color: var(--border); background: var(--surface-2); }
.usermenu .who { font-size: .85rem; font-weight: 560; }

.avatar {
  width: 30px; height: 30px; border-radius: 50%; flex: none;
  display: grid; place-items: center;
  background: var(--accent); color: var(--accent-contrast);
  font-weight: 700; font-size: .82rem; letter-spacing: .01em;
}
.avatar.lg { width: 42px; height: 42px; font-size: 1rem; }
.avatar.soft { background: var(--accent-soft); color: var(--accent); }
/* Bildet fyller sirkelen og beskjæres av den. `object-fit: cover` gjør at et
   portrett som ikke er helt kvadratisk ikke blir strukket — serveren tar imot
   kvadrater, men et gammelt bilde fra før den regelen skal fortsatt se ut. */
.avatar img { width: 100%; height: 100%; border-radius: 50%; object-fit: cover; display: block; }

/* ------------------------------- profil ------------------------------- */

/* To felt side om side der de hører sammen (fornavn/etternavn,
   postnummer/poststed). Under 520 px legger de seg under hverandre — to
   halve felt på en telefon blir to felt det ikke går an å skrive i. */
.felt-par { display: grid; grid-template-columns: 1fr 1fr; gap: 0 14px; }
@media (max-width: 520px) { .felt-par { grid-template-columns: 1fr; } }

.felt-bolk {
  font-size: .82rem; font-weight: 640; letter-spacing: .02em;
  color: var(--muted); margin: 18px 0 2px; text-transform: uppercase;
}

.avatar-forhand { display: grid; place-items: center; margin-bottom: 16px; }

.avatar-rutenett {
  display: grid; grid-template-columns: repeat(5, 1fr); gap: 8px; margin-top: 12px;
}
.avatar-rutenett button {
  aspect-ratio: 1; display: grid; place-items: center; border-radius: 12px;
  border: 1px solid var(--border); background: var(--surface-2); color: var(--text);
  cursor: pointer;
}
.avatar-rutenett button:hover { border-color: var(--accent); }
.avatar-rutenett button.on { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); }

.avatar-farger { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.avatar-farger button {
  width: 30px; height: 30px; border-radius: 50%; cursor: pointer;
  border: 2px solid transparent; box-shadow: 0 0 0 1px var(--border);
}
.avatar-farger button.on { border-color: var(--bg); box-shadow: 0 0 0 2px var(--accent); }
.avatar-farger button.auto {
  width: auto; height: 30px; padding: 0 12px; border-radius: 15px;
  background: var(--surface-2); color: var(--muted); font-size: .8rem;
}

/* ------------------- oppslag i offentlige registre ------------------- */

/* Forslagslista henger under feltet og skal ligge over alt annet i et
   skjema — også over feltet under, som ellers ville stukket gjennom. */
.sokforslag {
  display: none; position: absolute; z-index: 30; left: 0; right: 0; top: 100%;
  margin-top: 4px; max-height: 260px; overflow-y: auto; padding: 5px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-md); box-shadow: var(--shadow-lg);
}
.sokforslag.vis { display: block; }
.sokforslag button {
  display: block; width: 100%; text-align: left; cursor: pointer;
  padding: 8px 10px; border: 0; border-radius: var(--r-sm);
  background: transparent; color: var(--text); font: inherit;
}
.sokforslag button:hover { background: var(--surface-2); }
.sokforslag .n { display: block; font-size: .89rem; font-weight: 560; }
.sokforslag .d { display: block; font-size: .78rem; color: var(--faint); margin-top: 1px; }
.sok-tom { padding: 8px 10px; font-size: .8rem; color: var(--faint); }

/* Tilknytningskortene inne i et modalvindu skal ikke se ut som kort inni
   kortet — der er de bare to bolker i skjemaet. */
.stram .card { padding: 0; background: none; border: 0; box-shadow: none; margin: 0; }

.dropdown {
  position: absolute; right: 0; top: calc(100% + 8px); z-index: 50;
  min-width: 232px; padding: 6px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: var(--shadow-lg);
  animation: pop .16s var(--ease);
}
@keyframes pop { from { opacity: 0; transform: translateY(-6px) scale(.98); } }
.dropdown .dd-head { padding: 10px 10px 12px; border-bottom: 1px solid var(--border); margin-bottom: 6px; }
.dropdown .dd-head .name { font-weight: 620; }
.dropdown .dd-head .mail { font-size: .8rem; color: var(--muted); }
.dropdown button, .dropdown a {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 9px 10px; border-radius: var(--r-sm);
  font-size: .88rem; color: var(--text); text-align: left;
}
.dropdown button:hover, .dropdown a:hover { background: var(--surface-2); }
.dropdown .sep { height: 1px; background: var(--border); margin: 6px 4px; }
.dropdown .danger { color: var(--danger); }

/* ============================ Knapper ============================ */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 10px 17px; border-radius: var(--r-md);
  background: var(--accent); color: var(--accent-contrast);
  font-size: .91rem; font-weight: 620; letter-spacing: -.005em;
  border: 1px solid transparent; white-space: nowrap;
  transition: filter .15s, transform .1s var(--ease), background .15s, border-color .15s;
}
.btn:hover { filter: brightness(1.07); }
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: .5; cursor: not-allowed; transform: none; filter: none; }

.btn.secondary {
  background: var(--surface); color: var(--text); border-color: var(--border-strong);
}
.btn.secondary:hover { background: var(--surface-2); filter: none; }
.btn.ghost { background: transparent; color: var(--muted); }
.btn.ghost:hover { background: var(--surface-2); color: var(--text); filter: none; }
.btn.danger { background: var(--danger); color: #fff; }
.btn.danger.soft { background: var(--danger-soft); color: var(--danger); }
.btn.small { padding: 6px 12px; font-size: .84rem; border-radius: var(--r-sm); gap: 6px; }
.btn.wide { width: 100%; }
.btn.tiny { padding: 4px 9px; font-size: .78rem; border-radius: var(--r-sm); gap: 5px; }

/* Regelen sto lenge som `.btn .spinner`, og en snurring utenfor en knapp —
   i en notis, i en fremdriftsliste — var derfor et usynlig tomrom. */
.spinner {
  display: inline-block; width: 14px; height: 14px; border-radius: 50%;
  border: 2px solid currentColor; border-right-color: transparent;
  animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ============================ Skjema ============================ */

.field { display: block; margin-bottom: 14px; }
/* `hidden` er et attributt nettleseren gir `display: none`, men den regelen
   kommer fra nettleserens eget stilark og taper mot en klasse som setter
   `display` selv. Uten denne linja sto et felt med `hidden` igjen på
   skjermen — tomt, men fullt synlig og klart til å fylles ut. Det skjedde
   med linjevelgeren for en barneskole, som ikke skal ha noen linje i det
   hele tatt. */
.field[hidden] { display: none; }
.field > .lbl {
  display: block; font-size: .82rem; font-weight: 560;
  color: var(--muted); margin-bottom: 6px;
}
/* `.hint` har hele tiden bare vært stylet *inne i* et felt. Utenfor — tomme
   lister, forklaringer under en overskrift — arvet den brødteksten og ble
   like tung som innholdet den forklarte. Flere steder er det lappet på med
   `style="font-size:.8rem;color:var(--faint)"` i JS-en; nå står regelen her
   i stedet, og feltvarianten overstyrer den som før. */
.hint { font-size: .82rem; color: var(--faint); line-height: 1.5; }
.field .hint { font-size: .78rem; color: var(--faint); margin-top: 6px; line-height: 1.45; }
.field .bad { font-size: .8rem; color: var(--danger); margin-top: 6px; }

/* `tel` og `date` kom til med profilfeltene. Uten dem her tegner nettleseren
   sin egen boks midt i et skjema der alt annet er appens — og en dato-boks i
   systemstil er også lysere enn de mørke temaene, så den lyser opp. */
/* `input:not([type])` er ikke pynt: et felt uten type-attributt *oppfører*
   seg som text, men treffes ikke av `input[type=text]` — attributtvelgeren
   ser etter attributtet, ikke standardverdien. Start-stien under Felles
   innlogging har manglet den regelen siden den ble lagd, og sto som en smal
   systemboks midt i et skjema der alt annet var appens. */
/* `url` kom til med nettskrapingsbenken, der adressefeltet er det første man
   møter. Uten den her sto det som en smal systemboks ved siden av et
   fullbreddefelt i det samme skjemaet — tredje gang den samme utelatelsen har
   skjedd i denne lista, og grunnen er at et nytt felt velger typen sin etter
   hva som er riktig semantikk og ikke etter hva som står her. Skriver du et
   felt med en type som ikke står i denne rekka, hører den hjemme her. */
/* `file` står med vilje *ikke* her — det feltet er skjult og erstattet av
   `.filvelger` lenger nede. */
input[type=text], input[type=email], input[type=password],
input[type=number], input[type=search], input[type=tel], input[type=date],
input[type=url], input:not([type]), select, textarea {
  width: 100%;
  padding: 10px 13px;
  background: var(--surface-inset); color: var(--text);
  border: 1px solid var(--border); border-radius: var(--r-md);
  font: inherit; font-size: .92rem; outline: none;
  transition: border-color .15s, box-shadow .15s, background .15s;
}
input::placeholder, textarea::placeholder { color: var(--faint); }
input:focus, select:focus, textarea:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
input:disabled, select:disabled { opacity: .55; cursor: not-allowed; }

/* Et felt som fylles ut av noe annet enn deg — poststedet og kommunen som
   følger av postnummeret — skal se ut som det det er. Uten dette ser et
   låst felt akkurat ut som et du kan skrive i, og det leses som at appen
   har hengt seg. */
input[readonly] { color: var(--muted); cursor: default; }
input[readonly]:focus { border-color: var(--border); box-shadow: none; }
select {
  appearance: none;
  padding-right: 34px;
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 17px) 50%, calc(100% - 12px) 50%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}
textarea { resize: vertical; min-height: 84px; line-height: 1.5; }
input[type=checkbox] { accent-color: var(--accent); width: 16px; height: 16px; flex: none; }

/* Slippsonen for kontaktkort. Den er en helt vanlig knapperad til noe dras
   over den — da trer rammen fram, slik at det er tydelig at akkurat her kan
   du slippe. Uten den tilbakemeldingen ser et drag ut som om ingenting skjer
   før du allerede har sluppet. */
.kortrad {
  border: 1px dashed transparent; border-radius: var(--r-md);
  padding: 8px; margin-left: -8px; margin-right: -8px;
  transition: border-color .15s, background .15s;
}
.kortrad.over { border-color: var(--accent); background: var(--accent-soft); }
.kortrad.over * { pointer-events: none; }

/* Filvelger. Nettleserens egen «Choose File»-knapp er en systemknapp: den
   følger nettleserens språk og ikke appens, og den lar seg bare halvveis
   style. Her er den skjult, og etiketten rundt gjør at et klikk hvor som
   helst i feltet åpner den samme dialogen. */
.filvelger { display: flex; align-items: center; gap: 12px; min-width: 0; }
.filvelger input[type=file] { position: absolute; opacity: 0; width: 0; height: 0; }
.filvelger .knapp {
  font-size: .85rem; font-weight: 600; flex: none;
  padding: 7px 13px; border-radius: var(--r-sm);
  background: var(--surface-2); color: var(--text);
  border: 1px solid var(--border);
}
.filvelger:hover .knapp { border-color: var(--accent); }
.filvelger .filnavn {
  color: var(--muted); font-size: .9rem; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Av/på-bryter */
.switch { display: inline-flex; align-items: center; gap: 10px; cursor: pointer; }
.switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.switch .track {
  width: 40px; height: 23px; border-radius: var(--r-pill); flex: none;
  background: var(--surface-inset); border: 1px solid var(--border-strong);
  position: relative; transition: background .2s var(--ease), border-color .2s;
}
.switch .track::after {
  content: ""; position: absolute; top: 2px; left: 2px;
  width: 17px; height: 17px; border-radius: 50%;
  background: var(--muted); transition: transform .2s var(--ease), background .2s;
}
.switch input:checked + .track { background: var(--accent); border-color: var(--accent); }
.switch input:checked + .track::after { transform: translateX(17px); background: var(--accent-contrast); }
.switch input:focus-visible + .track { box-shadow: 0 0 0 3px var(--accent-soft); }
.switch .txt { font-size: .88rem; }

.checkline {
  display: flex; align-items: center; gap: 9px;
  font-size: .86rem; color: var(--muted); cursor: pointer;
}

/* ============================ Flater ============================ */

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow);
  padding: 20px;
}
.card + .card { margin-top: 14px; }
.card > .card-head {
  display: flex; align-items: flex-start; gap: 12px;
  margin: -2px 0 16px;
}
.card > .card-head .grow p { font-size: .84rem; color: var(--muted); margin-top: 3px; line-height: 1.45; }
/* Et hode med stempler *og* knapper får bryte. Uten dette sto merkene og de
   fire knappene på lydkortet i én rad som ikke kunne bli smalere enn 544 px,
   og på en telefon på 390 lå «Slett» utenfor kanten. Samme feil som
   .modal en gang hadde, og den ser man ikke på en utviklermaskin. */
.card > .card-head.wrap { flex-wrap: wrap; }
.card.flush { padding: 0; overflow: hidden; }
.card.flush > .card-head { padding: 18px 20px 0; margin-bottom: 12px; }

.section-title {
  display: flex; align-items: center; gap: 9px;
  font-size: .78rem; font-weight: 640; letter-spacing: .06em;
  text-transform: uppercase; color: var(--faint);
  margin: 30px 0 12px;
}
.section-title::after { content: ""; flex: 1; height: 1px; background: var(--border); }

.badge {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 9px; border-radius: var(--r-pill);
  font-size: .72rem; font-weight: 620; letter-spacing: .01em;
  background: var(--surface-2); color: var(--muted);
  border: 1px solid var(--border);
}
.badge.accent { background: var(--accent-soft); color: var(--accent); border-color: transparent; }
.badge.ok { background: var(--ok-soft); color: var(--ok); border-color: transparent; }
.badge.warn { background: var(--warn-soft); color: var(--warn); border-color: transparent; }
.badge.bad { background: var(--danger-soft); color: var(--danger); border-color: transparent; }
/* Et merke som står inne i en overskrift, ikke ved siden av den. */
.badge.liten { padding: 0 6px; font-size: .64rem; font-weight: 700; text-transform: uppercase; margin-left: 6px; }

.dot { width: 7px; height: 7px; border-radius: 50%; background: var(--faint); flex: none; }
.dot.ok { background: var(--ok); }
.dot.warn { background: var(--warn); }
.dot.bad { background: var(--danger); }

.empty {
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  padding: 40px 20px; text-align: center; color: var(--muted);
}
.empty .ico-wrap {
  width: 46px; height: 46px; border-radius: 14px;
  display: grid; place-items: center;
  background: var(--surface-2); color: var(--faint);
}
.empty h3 { font-size: .96rem; color: var(--text); }
.empty p { font-size: .86rem; max-width: 42ch; line-height: 1.5; }

.skeleton {
  border-radius: var(--r-sm);
  background: linear-gradient(100deg, var(--surface-2) 30%,
              color-mix(in srgb, var(--surface-2) 60%, var(--border)) 50%, var(--surface-2) 70%);
  background-size: 240% 100%;
  animation: shimmer 1.3s var(--ease) infinite;
}
@keyframes shimmer { from { background-position: 160% 0; } to { background-position: -60% 0; } }

/* ============================ Sider ============================ */

.page {
  flex: 1; width: 100%; max-width: var(--page-w);
  margin: 0 auto; padding: 22px clamp(14px, 3vw, 26px) 90px;
}
.page.narrow { max-width: 720px; }
.page-head { margin-bottom: 20px; }
.page-head h1 { font-size: 1.55rem; }
.page-head p { color: var(--muted); font-size: .9rem; margin-top: 4px; }
.page-head .row { margin-top: 0; }

/* ============================ Dashbord ============================ */

.dash { flex: 1; width: 100%; max-width: var(--page-w); margin: 0 auto;
        padding: clamp(20px, 5vh, 52px) clamp(14px, 3vw, 26px) 100px; }

/* Kort statusstripe: det som haster, i én linje */
.kpi-strip {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 10px; margin-bottom: 26px;
}
.kpi {
  display: flex; align-items: center; gap: 12px;
  padding: 13px 16px; border-radius: var(--r-md);
  background: var(--surface); border: 1px solid var(--border);
  color: var(--text); transition: border-color .15s, transform .15s var(--ease);
}
a.kpi:hover { border-color: var(--border-strong); transform: translateY(-1px); }
.kpi .kpi-ico {
  width: 34px; height: 34px; border-radius: 10px; flex: none;
  display: grid; place-items: center;
  background: var(--accent-soft); color: var(--accent);
}
.kpi b { font-size: 1.22rem; font-weight: 680; line-height: 1.1; display: block; }
.kpi span { font-size: .78rem; color: var(--muted); }

.module-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(212px, 1fr));
  gap: 12px;
}
/* `auto-fit` i stedet for `auto-fill`: den kollapser sporene ingen kort
   havner i, så ett kort blir like bredt som raden i stedet for å stå igjen
   på 212 px med tomrom ved siden av. Forskjellen vises bare når det er
   færre kort enn det er plass til — med en full rad er de to like.

   Den er en egen klasse og ikke standarden, fordi de to er riktige hver sin
   plass: en forside med to moduler skal ikke få to kort på en halv skjerm
   hver. Der det er *din ene* skolegang som står, er det motsatt. */
.module-grid.bred { grid-template-columns: repeat(auto-fit, minmax(212px, 1fr)); }

/* Et kort som fyller raden alene skal *leses* som en rad, ikke som en høy
   kolonne med alt i venstre hjørne og en halv skjerm tomrom ved siden av.
   Ikonet til venstre, navnet og stedet i midten, linja til høyre — samme
   form som kortene for Læringsportalen og invitasjonen rett under, så de
   tre leses som det samme slaget ting.

   `:only-child` og ikke klassen alene: er det to skolegangar, er hvert kort
   halve raden, og da er kolonnen riktig igjen. Og over 620 px, fordi en rad
   på en telefon er tre ting som slåss om 362 piksler. */
@media (min-width: 620px) {
  .module-grid.bred .module-card:only-child {
    flex-direction: row; align-items: center; gap: 18px;
    min-height: 0; padding: 18px 22px;
  }
  .module-grid.bred .module-card:only-child .m-ico {
    flex: none; width: 46px; height: 46px; border-radius: 13px;
  }
  .module-grid.bred .module-card:only-child .m-tekst { flex: 1 1 auto; min-width: 0; }
  .module-grid.bred .module-card:only-child .m-tekst h3 {
    margin: 0 0 2px; font-size: 1.06rem;
  }
  .module-grid.bred .module-card:only-child .m-foot {
    margin-top: 0; padding-top: 0; flex: none; padding-right: 26px;
  }
  /* Pila sentreres med `margin-top` og ikke med `transform`, fordi
     hover-regelen setter `transform: none` — en sentrering der hadde
     forsvunnet i det man pekte på kortet. */
  .module-grid.bred .module-card:only-child .m-arrow {
    top: 50%; margin-top: -8px;
  }
}

/* Hovedprosjektet på skolekortets rad, helt til høyre. En kort lenke ved
   siden av rutenettet og ikke et kort i det: da er skolekortet fortsatt
   `:only-child` og beholder radformen over. Samme høyde og samme form som
   skolekortet i radform, så de to leses som én rad. Under 620 px står lenka
   under, i full bredde — to ting side om side på en telefon er for trangt. */
.skole-rad { display: flex; gap: 12px; align-items: stretch; }
.skole-rad > .module-grid { flex: 1 1 auto; min-width: 0; }
.skole-rad > .hp-snarvei {
  flex: 0 0 auto; width: 290px; min-height: 0;
  flex-direction: row; align-items: center; gap: 14px; padding: 18px 40px 18px 18px;
}
.skole-rad .hp-snarvei .m-ico { flex: none; }
.skole-rad .hp-snarvei .m-tekst { min-width: 0; }
.skole-rad .hp-snarvei h3 { margin: 0 0 2px; }
/* Prosjektnavnet kan være langt («Separat utnyttelse av … »): to linjer, så
   kuttes det. Hele står i `title`. */
.skole-rad .hp-snarvei p {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.skole-rad .hp-snarvei .m-arrow { top: 50%; margin-top: -8px; }
/* Tallene under navnet — emner i fagene, steg i hovedprosjektet — med en
   stolpe. Raden blir høyere av dem, og det er meningen: de er det man ser
   etter når man åpner skolesiden. */
.skole-stat { display: block; margin-top: 10px; padding-top: 9px; border-top: 1px solid var(--border); }
.skole-stat .ss-tall { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 6px; margin-bottom: 7px; }
.skole-stat b { font-size: 1.05rem; font-weight: 700; color: var(--accent); font-variant-numeric: tabular-nums; }
.skole-stat .ss-tall > span { font-size: .75rem; color: var(--muted); margin-right: 8px; }
.skole-stat .skeleton { display: block; height: 15px; width: 60%; }
.skole-rad .module-card { align-self: stretch; }
@media (max-width: 619px) {
  .skole-rad { flex-direction: column; }
  .skole-rad > .hp-snarvei { width: auto; }
}

/* `text-align: left` fordi flisa også brukes som <button> — gruppeflisene
   på verktøysiden fører til en fane og ikke til en adresse. En <a> arver
   venstre uansett, en <button> sentrerer. */
.module-card {
  position: relative; display: flex; flex-direction: column;
  padding: 17px; min-height: 148px; text-align: left;
  color: var(--text);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: var(--shadow);
  transition: transform .16s var(--ease), border-color .16s, box-shadow .16s;
}
.module-card:hover {
  transform: translateY(-2px);
  border-color: var(--border-strong);
  box-shadow: var(--shadow-lg);
}
.module-card:hover .m-ico { background: var(--accent); color: var(--accent-contrast); }
.module-card .m-ico {
  width: 38px; height: 38px; border-radius: 11px;
  display: grid; place-items: center;
  background: var(--accent-soft); color: var(--accent);
  transition: background .16s, color .16s;
}
.module-card h3 { margin: 13px 0 3px; font-size: .98rem; }
.module-card p { font-size: .81rem; color: var(--muted); line-height: 1.4; }
.module-card .m-foot { margin-top: auto; padding-top: 13px; }
.module-card .m-arrow {
  position: absolute; top: 17px; right: 15px;
  color: var(--faint); opacity: 0; transform: translateX(-3px);
  transition: opacity .16s, transform .16s var(--ease);
}
.module-card:hover .m-arrow { opacity: 1; transform: none; }

/* Levende tall fra tjenestene */
.m-stat {
  display: flex; align-items: baseline; gap: 7px; flex-wrap: wrap;
  padding-top: 11px; border-top: 1px solid var(--border);
}
.m-stat b {
  font-size: 1.18rem; font-weight: 700; color: var(--accent);
  line-height: 1; white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.m-stat span { font-size: .75rem; color: var(--muted); }
.m-stat.bad { color: var(--danger); }
.m-stat.bad span { color: var(--danger); }
.m-stat .skeleton { height: 15px; width: 66%; }

/* Ukesgrafen, til høyre på den samme linja som tallet. `margin-left: auto`
   skyver den ut i plassen som sto tom der; en egen rad under ville kostet
   31 px på kortet, og rutenettet ville sendt regninga videre til hele raden.

   `flex: none` fordi den er et flex-barn: uten den krympes stolpene når
   detaljteksten kjemper om plassen, og sju dager blir sju streker. */
.m-graf { flex: none; width: 74px; margin-left: auto; overflow: visible; }
.m-graf rect { fill: var(--accent); }
/* En dag uten noe skal leses som null, ikke som manglende data — derfor en
   strek i samme farge, dempet, og ikke et hull i rekka. */
.m-graf rect.tom { fill: var(--border-strong); }

.m-flag {
  position: absolute; top: 15px; right: 15px;
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 8px; border-radius: var(--r-pill);
  font-size: .68rem; font-weight: 640; letter-spacing: .02em;
  background: var(--warn-soft); color: var(--warn);
}
.module-card.disabled { opacity: .55; pointer-events: none; }
.module-card.disabled .m-ico { background: var(--surface-2); color: var(--faint); }

/* Produktlogoer på modulflisene — se modIkon() i app.js for når de brukes.
   En logo er et bilde og lar seg ikke omfarge, så flisa gir fra seg både
   aksentfyllet og fargeskiftet på hover: merket skal se ut som seg selv i
   alle seks temaene. Flisa beholder målene sine, slik at rutenettet har
   samme rytme enten modulen har logo eller ikon. Kortet svarer fortsatt på
   mus, bare med et nikk i stedet for et fargeskift. */
.mod-logo { object-fit: contain; display: block; }
.modul-navn .mod-logo { flex: none; }
.m-ico.har-logo,
.module-card:hover .m-ico.har-logo,
.module-card.disabled .m-ico.har-logo,
.pick .p-ico.har-logo,
.pick.on .p-ico.har-logo { background: none; color: inherit; }
.module-card .m-ico.har-logo { transition: transform .16s var(--ease); }
.module-card:hover .m-ico.har-logo { transform: scale(1.07); }

.hh-chip {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 8px 15px; border-radius: var(--r-pill);
  font-size: .85rem; color: var(--muted);
  background: var(--surface); border: 1px solid var(--border);
}
/* Brikka er en <a> når den fører et sted og en <button> når den åpner et
   vindu — skolebrikka i hilsenskortet gjør det siste. Knappen arver ikke
   skrift, og den sentrerer teksten; begge deler må settes, ellers står den
   med nettleserens egen skrift midtstilt inni en pille som ellers er lik.
   Hover-regelen gjaldt bare `a` og lot knappen stå død under pekeren. */
button.hh-chip {
  font: inherit; font-size: .85rem; text-align: left; cursor: pointer;
}
a.hh-chip:hover, button.hh-chip:hover {
  border-color: var(--border-strong); color: var(--text);
}

/* ==================== husstandssiden og profilsidene ==================== */

.hh-adresselinje {
  display: flex; align-items: center; gap: 7px; flex-wrap: wrap;
  color: var(--muted); font-size: .9rem; margin-top: 6px;
}

.medlem-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(178px, 1fr));
  gap: 12px;
}

/* Samme kropp som modulkortene, med profilbildet i en runding i hjørnet. */
.medlem-kort {
  position: relative; display: block;
  padding: 17px; padding-right: 74px; min-height: 96px;
  color: var(--text);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: var(--shadow);
  transition: transform .16s var(--ease), border-color .16s, box-shadow .16s;
}
.medlem-kort:hover {
  transform: translateY(-2px);
  border-color: var(--border-strong);
  box-shadow: var(--shadow-lg);
}
.medlem-kort .mk-avatar { position: absolute; top: 14px; right: 14px; }
.medlem-kort h3 { font-size: .95rem; margin-top: 4px; }
.medlem-kort p { font-size: .79rem; color: var(--muted); margin-top: 3px; line-height: 1.4; }
.medlem-kort .mk-pil {
  position: absolute; bottom: 15px; right: 15px;
  color: var(--faint); opacity: 0; transform: translateX(-3px);
  transition: opacity .16s, transform .16s var(--ease);
}
.medlem-kort:hover .mk-pil { opacity: 1; transform: none; }

.tilbakelenke {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: .84rem; color: var(--muted); margin-bottom: 14px;
}
.tilbakelenke:hover { color: var(--text); }

.profil-hode {
  display: flex; align-items: center; gap: 18px; flex-wrap: wrap;
  background: linear-gradient(140deg, var(--accent-soft), var(--surface) 60%);
}
.profil-hode h1 { font-size: 1.35rem; }
.profil-hode p { color: var(--muted); font-size: .87rem; margin-top: 4px; }
.mp-kallenavn { color: var(--muted); font-weight: 480; font-size: 1.05rem; }

/* Kontakten i hodekortet — telefon, e-post og adresse som små linjer under
   linja med alder og fødselsdato. */
.ph-kontakt {
  display: flex; flex-direction: column; gap: 5px;
  margin-top: 10px; font-size: .86rem;
}
.ph-kontakt a, .ph-kontakt > span {
  display: inline-flex; align-items: center; gap: 8px;
  color: var(--text); min-width: 0; overflow-wrap: anywhere;
}
.ph-kontakt svg { color: var(--muted); flex: none; }
.ph-kontakt a:hover { color: var(--accent); }
.ph-hint { color: var(--faint); font-style: normal; font-size: .78rem; }

/* Profilen som fliser — én opplysning per flis, ikke rader i en liste. */
.profil-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(224px, 1fr));
  gap: 12px; margin-top: 14px;
}
.flis {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 15px; text-align: left;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: var(--shadow);
}
.flis-ico {
  width: 36px; height: 36px; border-radius: 10px; flex: none;
  display: grid; place-items: center;
  background: var(--accent-soft); color: var(--accent);
}
.flis-innhold { min-width: 0; }
.flis-lbl {
  display: block; font-size: .66rem; font-weight: 660;
  letter-spacing: .07em; text-transform: uppercase; color: var(--faint);
}
.flis-verdi {
  display: block; font-size: .93rem; font-weight: 620;
  margin-top: 3px; line-height: 1.35; overflow-wrap: anywhere;
}
.flis-sub { display: block; font-size: .78rem; color: var(--muted); margin-top: 3px; line-height: 1.4; }
.flis.varsom .flis-ico { background: var(--warn-soft); color: var(--warn); }
.flis .flis-endre { margin-left: auto; flex: none; }
.flis-ny {
  border-style: dashed; background: none; box-shadow: none;
  align-items: center; justify-content: center; gap: 7px;
  color: var(--muted); font-size: .83rem; font-weight: 560;
  cursor: pointer; min-height: 66px;
}
.flis-ny:hover { border-color: var(--accent); color: var(--accent); }

/* Redigeringskontrollene er skjult til «Rediger»-knappen setter .redigering
   på siden — et dashbord fullt av blyanter leses som et skjema. */
.flis-endre, .flis-ny, .hh-endre, .mk-endre { display: none; }
.redigering .flis-endre { display: inline-flex; }
.redigering .flis-ny { display: flex; }
.redigering .hh-endre { display: inline-flex; }
.redigering .mk-endre { display: grid; }

/* Blyanten på et barnekort — samme hjørne som pila, som skjules i modusen. */
.mk-endre {
  position: absolute; bottom: 12px; right: 12px;
  width: 28px; height: 28px; place-items: center;
  border-radius: 8px; border: 1px solid var(--border);
  background: var(--surface-2); color: var(--muted); cursor: pointer;
}
.mk-endre:hover { color: var(--accent); border-color: var(--accent); }
.redigering .medlem-kort .mk-pil { display: none; }
/* Litt mer høyde i modusen, så blyanten ikke ligger oppå profilbildet. */
.redigering .medlem-kort { min-height: 120px; }

/* ============================ Lister og rader ============================ */

.rows { display: flex; flex-direction: column; }
.rows > .rw {
  display: flex; align-items: center; gap: 12px;
  padding: 11px 0; border-bottom: 1px solid var(--border);
}
.rows > .rw:last-child { border-bottom: none; }
.rows.boxed > .rw { padding: 11px 16px; }
.rows.boxed > .rw:hover { background: var(--surface-2); }
.rw .who .name { font-weight: 590; font-size: .92rem; display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.rw .who .mail { font-size: .79rem; color: var(--muted); margin-top: 1px; }
.rw .acts { display: flex; align-items: center; gap: 6px; margin-left: auto; }

/* Innstillinger → E-postadresser. Raden er adresse, type, og hva man kan
   gjøre med den. På en telefon får ikke alle tre plass på én linje, og det
   som ryker er adressen — den kortes til «kim.robi…», og da er raden en
   liste over adresser der adressen ikke står. Under 560 px legger den seg
   derfor om: adressen på sin egen linje, merket og knappene under. */
@media (max-width: 560px) {
  .rows.eposter > .rw { flex-wrap: wrap; gap: 8px; }
  .rows.eposter > .rw > .truncate { flex: 1 1 100%; }
}

/* Invitasjonene og slettelista i Administrasjon → Brukere. Raden er et navn,
   ett eller to merker og to knapper, og på en telefon får de ikke plass på
   samme linje. Det som ryker er navnet: «Sara Hansen» brekkes midt i to ord
   mens datoen under blir en spalte på fire tegn. Under 560 px legger raden
   seg derfor om med knappene på sin egen linje — samme grep og samme grunn
   som `.rows.eposter` over. */
@media (max-width: 560px) {
  .rows.brekk > .rw { flex-wrap: wrap; gap: 8px 12px; }
  .rows.brekk > .rw .who { flex: 1 1 100%; }
  .rows.brekk > .rw .acts { margin-left: 0; flex: 1 1 100%; }
}

.invite-code {
  display: inline-block;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 1.18rem; letter-spacing: .1em; font-weight: 700;
  color: var(--accent); background: var(--accent-soft);
  padding: 8px 15px; border-radius: var(--r-md);
}

/* Gjøremål og handleliste */
.additem { display: flex; gap: 8px; }
.additem input { flex: 1; }
.tlist { list-style: none; }
.tlist li {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 2px; border-bottom: 1px solid var(--border);
}
.tlist li:last-child { border-bottom: none; }
.tlist li.done .title { color: var(--faint); text-decoration: line-through; }
.tlist .title { flex: 1; min-width: 0; font-size: .93rem; }
.tlist .amount {
  margin-left: 8px; font-size: .79rem; color: var(--muted);
  background: var(--surface-2); padding: 1px 7px; border-radius: var(--r-pill);
}
.tick-btn {
  width: 21px; height: 21px; border-radius: 7px; flex: none;
  border: 1.8px solid var(--border-strong); background: transparent;
  display: grid; place-items: center; color: transparent;
  transition: background .15s, border-color .15s, color .15s;
}
.tick-btn:hover { border-color: var(--accent); }
.tlist li.done .tick-btn {
  background: var(--accent); border-color: var(--accent); color: var(--accent-contrast);
}
.row-del { color: var(--faint); padding: 4px; border-radius: var(--r-sm); display: grid; place-items: center; }
.row-del:hover { color: var(--danger); background: var(--danger-soft); }
.tag {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: .72rem; color: var(--muted);
  padding: 2px 8px; border-radius: var(--r-pill); background: var(--surface-2);
}

/* ========================== Samværsplan ==========================

   Uke og måned er det samme rutenettet med to ulike cellehøyder — sju
   kolonner, mandag først. Å tegne uka som en liste og måneden som et
   rutenett hadde gitt to komponenter å holde i takt, og ingen av dem ville
   vist rytmen bedre.

   Fargen sier hvor barnet er, og prikken sier det en gang til: fylt for
   «her», ring for «hos den andre». To merkefarger ved siden av hverandre er
   ikke nok alene, og en samværskalender skal kunne leses raskt og sikkert.
   Rammen rundt cellen bærer den samme forskjellen, så den overlever et
   skjermbilde i gråtoner. */

.sv-barn { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 14px; }
.sv-barnknapp {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 5px 12px 5px 5px; border-radius: var(--r-pill);
  background: var(--surface); border: 1px solid var(--border);
  font-size: .86rem; font-weight: 550; color: var(--muted);
  transition: border-color .15s, color .15s;
}
.sv-barnknapp:hover { color: var(--text); }
.sv-barnknapp.on { color: var(--text); border-color: var(--border-strong); background: var(--surface-2); }

/* «Velg barn» står i samme rad som barneknappene, men er ikke en av dem —
   stiplet kant sier at den åpner noe i stedet for å bytte hvem du ser på. */
.sv-barnknapp.velg {
  border-style: dashed; padding-left: 12px; gap: 7px;
}
.sv-barnknapp.velg:hover { border-color: var(--accent); color: var(--accent); }

.sv-velg { display: flex; flex-direction: column; gap: 4px; }
.sv-velg-rad {
  display: flex; align-items: center; gap: 11px;
  padding: 9px 12px; border-radius: var(--r-md);
  border: 1px solid transparent; cursor: pointer;
  font-size: .92rem; font-weight: 550;
}
.sv-velg-rad:hover { background: var(--surface-2); }
.sv-velg-rad input { width: 17px; height: 17px; accent-color: var(--accent); flex: none; }
.sv-velg-rad:has(input:checked) { border-color: color-mix(in srgb, var(--accent) 40%, transparent); background: var(--accent-soft); }

.sv-nokler { display: flex; flex-wrap: wrap; gap: 14px; margin-bottom: 10px; }
.sv-nokkel { display: inline-flex; align-items: center; gap: 7px; font-size: .82rem; color: var(--muted); }

.sv-prikk {
  width: 11px; height: 11px; border-radius: 50%; flex: none;
  border: 2px solid var(--muted);
}
.sv-prikk.her { background: var(--accent); border-color: var(--accent); }
.sv-prikk.andre { background: transparent; border-color: var(--accent-2); }
.sv-prikk.tom { border-style: dashed; border-color: var(--faint); }

.sv-rutenett {
  display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 6px;
}
.sv-merke { display: flex; align-items: center; gap: 6px; min-width: 0; }
.sv-dag {
  display: flex; flex-direction: column; gap: 5px; align-items: stretch;
  padding: 8px 8px 9px; border-radius: var(--r-md); text-align: left;
  background: var(--surface-inset); border: 1px solid var(--border);
  color: var(--text); min-height: 62px;
  transition: border-color .15s, background .15s;
}
button.sv-dag:hover { border-color: var(--border-strong); }
button.sv-dag:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.sv-dag.blank { background: none; border-color: transparent; min-height: 0; }
.sv-dag.her {
  background-color: var(--accent-soft);
  border-color: color-mix(in srgb, var(--accent) 45%, transparent);
}
/* Skravur og ikke bare en annen farge. To merkefarger kan ligge tett i tema
   etter tema — i Nordlys er de begge grønnaktige — og da leses hele uka som
   én tilstand. Skravuren skiller flatene uansett palett, også i gråtoner. */
.sv-dag.andre {
  background-color: color-mix(in srgb, var(--accent-2) 9%, transparent);
  background-image: repeating-linear-gradient(135deg,
    color-mix(in srgb, var(--accent-2) 22%, transparent) 0 1.5px,
    transparent 1.5px 10px);
  border-color: color-mix(in srgb, var(--accent-2) 50%, transparent);
  border-style: dashed;
}
.sv-dag.idag { box-shadow: inset 0 0 0 1.5px var(--text); }
.sv-dag.helg .sv-ukedag { color: var(--warn); }

.sv-dag-topp { display: flex; align-items: baseline; justify-content: space-between; gap: 4px; }
.sv-ukedag { font-size: .68rem; font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }
.sv-tall { font-size: .9rem; font-weight: 600; font-variant-numeric: tabular-nums; }
.sv-etikett {
  font-size: .73rem; font-weight: 600; color: var(--muted); line-height: 1.25;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sv-dag.her .sv-etikett { color: var(--accent); }
.sv-dag.andre .sv-etikett { color: var(--accent-2); }
.sv-notat {
  font-size: .72rem; color: var(--muted); line-height: 1.35;
  overflow: hidden; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
}

/* Uka har plass til mer per dag enn måneden — samme rutenett, høyere celler
   og hele ukedagsnavnet ville sprengt en månedskolonne på telefon. */
.sv-rutenett.uke .sv-dag { min-height: 104px; }
.sv-rutenett.maned .sv-dag { min-height: 54px; }
.sv-rutenett.maned .sv-notat,
.sv-rutenett.maned .sv-etikett { display: none; }

/* Årsoversikten: tolv små måneder. Bredden styres av `auto-fill` og en
   minstebredde per måned, ikke av et fast antall kolonner — en måned med
   sju kolonner à 24 px har en naturlig minstebredde, og da faller
   oppsettet fra fire til tre til to til én av seg selv. */
.sv-aar {
  display: grid; gap: 18px 16px;
  grid-template-columns: repeat(auto-fill, minmax(196px, 1fr));
}
.sv-maned-navn {
  display: block; width: 100%; text-align: left; padding: 2px 2px 7px;
  font-size: .84rem; font-weight: 600; color: var(--muted);
  transition: color .15s;
}
.sv-maned-navn:hover { color: var(--accent); }
.sv-maned-dager { display: grid; grid-template-columns: repeat(7, 1fr); gap: 3px; }
.sv-maned-dager + .sv-maned-dager { margin-top: 3px; }
.sv-aar-hode {
  display: flex; align-items: center; justify-content: center;
  font-size: .58rem; font-weight: 700; color: var(--faint);
  text-transform: uppercase; letter-spacing: .03em; padding-bottom: 1px;
}
.sv-aar-hode.helg { color: var(--warn); }

.sv-aar-dag {
  display: flex; align-items: center; justify-content: center;
  aspect-ratio: 1; min-height: 22px; border-radius: 5px;
  font-size: .63rem; font-variant-numeric: tabular-nums;
  background: var(--surface-inset); border: 1px solid var(--border);
  color: var(--muted); position: relative;
  transition: border-color .12s;
}
button.sv-aar-dag:hover { border-color: var(--border-strong); color: var(--text); }
button.sv-aar-dag:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.sv-aar-dag.blank { background: none; border-color: transparent; }
.sv-aar-dag.her {
  background-color: var(--accent-soft); color: var(--text);
  border-color: color-mix(in srgb, var(--accent) 45%, transparent);
}
/* Samme skravur som i uke og måned, i mindre målestokk — det er den som
   gjør at et halvt år med annenhver uke leses som et mønster og ikke som
   en flate med to nesten like grønnfarger. */
.sv-aar-dag.andre {
  background-color: color-mix(in srgb, var(--accent-2) 9%, transparent);
  background-image: repeating-linear-gradient(135deg,
    color-mix(in srgb, var(--accent-2) 30%, transparent) 0 1px,
    transparent 1px 5px);
  border-color: color-mix(in srgb, var(--accent-2) 50%, transparent);
  color: var(--text);
}
.sv-aar-dag.helg { font-weight: 600; }
.sv-aar-dag.idag { box-shadow: inset 0 0 0 1.5px var(--text); }
/* En dag med notat får et hakk i hjørnet. Teksten får ikke plass på 22 px,
   men «det står noe her» er nettopp det man trenger for å vite hvor man
   skal åpne. */
.sv-aar-dag.notat::after {
  content: ''; position: absolute; top: 1.5px; right: 1.5px;
  width: 3.5px; height: 3.5px; border-radius: 50%; background: var(--text);
}

@media (max-width: 560px) {
  .sv-aar { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 14px 12px; }
  .sv-aar-dag { min-height: 18px; font-size: .58rem; border-radius: 4px; }
}

/* De to stedene side om side. Under 620 px legges de under hverandre —
   to spalter på en telefon gir navn som brekker midt i et ord. */
.sv-steder {
  display: grid; gap: 14px;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
}
.sv-sted {
  padding: 12px 14px; border-radius: var(--r-md);
  background: var(--surface-inset); border: 1px solid var(--border);
}
.sv-sted-topp { display: flex; align-items: center; gap: 8px; margin-bottom: 7px; }
.sv-sted-merke {
  font-size: .72rem; font-weight: 700; color: var(--muted);
  text-transform: uppercase; letter-spacing: .04em;
}
.sv-sted-navn { font-weight: 600; font-size: 1rem; margin-bottom: 4px; }

/* Overskrift over en bolk i et skjema, med den samme prikken som i
   kalenderen — det er den som sier hvilket av de to stedene bolken gjelder. */
.sv-bolk {
  display: flex; align-items: center; gap: 8px;
  font-size: .82rem; font-weight: 700; color: var(--muted);
  text-transform: uppercase; letter-spacing: .04em;
  margin: 0 0 10px; padding-bottom: 8px; border-bottom: 1px solid var(--border);
}

.sv-forelder { display: flex; flex-wrap: wrap; gap: 14px; align-items: flex-start; }
.sv-forelder-navn { font-weight: 600; font-size: .95rem; margin-bottom: 3px; }
.sv-konto {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 12px 8px 8px; border-radius: var(--r-pill);
  background: var(--surface-2); border: 1px solid var(--border);
}

/* Setningen som leser rytmen tilbake. Den står som en flate og ikke som en
   hint-linje fordi den er svaret på «ble det det jeg mente?» — «Hver 3. uke»
   og «hver tredje fredag» er to forskjellige avtaler, og feltene alene
   skiller dem ikke. */
.sv-rytme {
  margin: 10px 0 0; padding: 9px 12px; border-radius: var(--r-md);
  background: var(--accent-soft); color: var(--accent);
  font-size: .87rem; font-weight: 600;
}

.sv-ukedager { display: flex; flex-wrap: wrap; gap: 6px; }
.sv-ukedag-valg { position: relative; }
.sv-ukedag-valg input { position: absolute; opacity: 0; width: 0; height: 0; }
.sv-ukedag-valg span {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 38px; padding: 7px 4px; border-radius: var(--r-sm);
  background: var(--surface-inset); border: 1px solid var(--border);
  font-size: .8rem; font-weight: 600; color: var(--muted); cursor: pointer;
}
.sv-ukedag-valg input:checked + span {
  background: var(--accent-soft); border-color: var(--accent); color: var(--accent);
}
.sv-ukedag-valg input:focus-visible + span { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Dashbordet øverst: hvor barnet er i dag, neste bytte, rulleringen. Samme
   `.kpi` som forsiden, så tallene leses likt overalt. */
.sv-dash { margin-bottom: 14px; }
.sv-dash .kpi b { font-size: 1.02rem; }
.sv-prikk.inline { display: inline-block; vertical-align: -1px; width: 9px; height: 9px; margin-left: 3px; }
.sv-stegnavn {
  font-size: .76rem; font-weight: 700; color: var(--muted);
  text-transform: uppercase; letter-spacing: .04em; margin: -6px 0 12px;
}

/* Et avvik fra rulleringen får et hakk i hjørnet i varselfargen. Det er
   ikke en feil — det er «denne dagen er satt for hånd», og det er nettopp
   det man leter etter når to utgaver av planen ikke stemmer. */
.sv-dag { position: relative; }
.sv-avvik-merke {
  width: 0; height: 0; flex: none;
  border-style: solid; border-width: 0 11px 11px 0;
  border-color: transparent var(--warn) transparent transparent;
}
.sv-dag.avvik::after {
  content: ''; position: absolute; top: -1px; right: -1px;
  border-style: solid; border-width: 0 12px 12px 0;
  border-color: transparent var(--warn) transparent transparent;
  border-top-right-radius: var(--r-md);
}
.sv-aar-dag.avvik::after {
  content: ''; position: absolute; top: 1.5px; right: 1.5px;
  width: 3.5px; height: 3.5px; border-radius: 50%; background: var(--warn);
}

/* Kallenavn-knappene over navnefeltet. Samme form som ukedagsvalgene —
   det er den samme tingen: et sett faste alternativer foran et fritt felt. */
.sv-kallenavn { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 8px; }
.sv-kallenavn button {
  padding: 5px 11px; border-radius: var(--r-pill);
  background: var(--surface-inset); border: 1px solid var(--border);
  font-size: .8rem; font-weight: 600; color: var(--muted);
  transition: border-color .15s, color .15s, background .15s;
}
.sv-kallenavn button:hover { border-color: var(--border-strong); color: var(--text); }
.sv-kallenavn button.on { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); }

/* Rulleringsredigeringen: ukenummer i første kolonne, sju dager etter.
   Cellene har samme flate og skravur som kalenderen, så det man fyller inn
   her ser ut som det kalenderen kommer til å vise. */
.sv-rull {
  display: grid; grid-template-columns: 30px repeat(7, minmax(0, 1fr));
  gap: 5px; align-items: stretch;
}
.sv-rull-hode {
  display: flex; align-items: flex-end; justify-content: center; padding-bottom: 2px;
  font-size: .64rem; font-weight: 700; color: var(--faint);
  text-transform: uppercase; letter-spacing: .04em;
}
.sv-rull-hode.helg { color: var(--warn); }
.sv-rull-uke {
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--r-sm); font-size: .74rem; font-weight: 700; color: var(--muted);
  background: var(--surface-2); border: 1px solid var(--border);
  transition: border-color .15s, color .15s;
}
.sv-rull-uke:hover { border-color: var(--accent); color: var(--accent); }
.sv-rull-dag {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px;
  min-height: 46px; padding: 5px 2px; border-radius: var(--r-sm);
  background: var(--surface-inset); border: 1px solid var(--border);
  font-size: .8rem; font-weight: 600; font-variant-numeric: tabular-nums; color: var(--text);
  transition: border-color .12s, background .12s;
}
button.sv-rull-dag:hover { border-color: var(--border-strong); }
button.sv-rull-dag:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.sv-rull-dag.her {
  background-color: var(--accent-soft);
  border-color: color-mix(in srgb, var(--accent) 45%, transparent);
}
.sv-rull-dag.andre {
  background-color: color-mix(in srgb, var(--accent-2) 9%, transparent);
  background-image: repeating-linear-gradient(135deg,
    color-mix(in srgb, var(--accent-2) 22%, transparent) 0 1.5px,
    transparent 1.5px 10px);
  border-color: color-mix(in srgb, var(--accent-2) 50%, transparent);
  border-style: dashed;
}
.sv-rull-dag.utenfor {
  background: none; border-style: dotted; color: var(--faint); font-weight: 500;
  cursor: not-allowed;
}
.sv-rull-dag.start { box-shadow: inset 0 0 0 1.5px var(--text); }
.sv-rull-dag .sv-prikk { width: 9px; height: 9px; }

@media (max-width: 560px) {
  .sv-rull { gap: 3px; grid-template-columns: 24px repeat(7, minmax(0, 1fr)); }
  .sv-rull-dag { min-height: 40px; font-size: .72rem; gap: 3px; }
  .sv-rull-dag .sv-prikk { width: 7px; height: 7px; }
  .sv-dash { grid-template-columns: 1fr; gap: 8px; }
}

/* På telefon blir sju kolonner sju ruter på 46 px, og da står det «A.» der
   det skulle stått hvem barnet er hos. Uka legges derfor om til én rad per
   dag — samme grep som ukemenyen bruker. Måneden beholder rutenettet: der er
   ruta uansett bare et tall og en prikk, og det er rytmen man ser etter. */
@media (max-width: 560px) {
  .sv-rutenett { gap: 4px; }
  .sv-dag { padding: 6px 5px 7px; }
  .sv-ukedag { font-size: .62rem; }

  .sv-rutenett.uke { grid-template-columns: 1fr; gap: 5px; }
  .sv-rutenett.uke .sv-dag {
    flex-direction: row; align-items: center; gap: 10px;
    min-height: 0; padding: 9px 12px;
  }
  .sv-rutenett.uke .sv-dag-topp { flex: none; width: 46px; gap: 7px; justify-content: flex-start; }
  .sv-rutenett.uke .sv-ukedag { font-size: .68rem; }
  .sv-rutenett.uke .sv-merke { flex: none; }
  .sv-rutenett.uke .sv-etikett { max-width: 11ch; }
  .sv-rutenett.uke .sv-notat {
    flex: 1; min-width: 0; text-align: right; -webkit-line-clamp: 2;
  }
}

/* ============================ Ukemeny ============================ */

.week-nav { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 6px; }
.week-nav .lbl { font-size: .86rem; color: var(--muted); font-weight: 550; }

.day-row { display: flex; gap: 14px; padding: 11px 0; border-bottom: 1px solid var(--border); }
.day-row:last-child { border-bottom: none; }
.day-row.today { background: var(--accent-soft); margin: 0 -12px; padding: 11px 12px; border-radius: var(--r-md); border-bottom-color: transparent; }
.day-row.today .day-name { color: var(--accent); }
.day-name { width: 104px; flex: none; font-weight: 600; font-size: .89rem; display: flex; flex-direction: column; }
.day-date { font-size: .74rem; color: var(--muted); font-weight: 400; font-variant-numeric: tabular-nums; }
.day-meals { flex: 1; display: flex; flex-wrap: wrap; gap: 7px; align-items: center; }
.meal {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 5px 7px 5px 12px; border-radius: var(--r-pill);
  background: var(--surface-2); border: 1px solid var(--border); font-size: .85rem;
}
.meal a { color: var(--text); }
.meal a:hover { color: var(--accent); }

.rec-list { max-height: 330px; overflow-y: auto; margin-top: 10px; }
.rec-item {
  display: flex; align-items: center; gap: 10px; width: 100%;
  text-align: left; padding: 9px 11px; border-radius: var(--r-md);
  border: 1px solid transparent; color: var(--text);
}
.rec-item:hover { background: var(--surface-2); border-color: var(--border); }
.rec-item .t { flex: 1; font-size: .9rem; }
.rec-item .c {
  font-size: .71rem; padding: 2px 8px; border-radius: var(--r-pill);
  background: var(--surface-2); color: var(--muted); border: 1px solid var(--border);
}
.rec-item .i { font-size: .73rem; color: var(--faint); }

/* ============================ Faner ============================ */

.tabs {
  display: flex; gap: 3px; overflow-x: auto; scrollbar-width: none;
  padding: 3px; margin-bottom: 18px;
  background: var(--surface-inset); border: 1px solid var(--border);
  border-radius: var(--r-md);
}
.tabs::-webkit-scrollbar { display: none; }
.tabs button {
  display: inline-flex; align-items: center; gap: 7px; white-space: nowrap;
  padding: 8px 14px; border-radius: var(--r-sm);
  font-size: .87rem; font-weight: 570; color: var(--muted);
  transition: background .16s, color .16s;
}
.tabs button:hover { color: var(--text); }
.tabs button.on { background: var(--surface); color: var(--text); box-shadow: var(--shadow); }

/* Jobbvelgeren i Arbeid: husets fanerekke, men med lenker. Den er
   navigasjon og ikke en bryter — hver jobb har sin egen adresse
   (`#/arbeid/<selskap>`), så den kan bokmerkes og tilbakeknappen virker.
   Reglene er `.tabs button` sine, gjentatt for `a` fordi selektoren der er
   elementspesifikk. */
.tabs.jobbvelger a {
  display: inline-flex; align-items: center; gap: 7px; white-space: nowrap;
  padding: 8px 14px; border-radius: var(--r-sm);
  font-size: .87rem; font-weight: 570; color: var(--muted);
  transition: background .16s, color .16s;
}
.tabs.jobbvelger a:hover { color: var(--text); }
.tabs.jobbvelger a.on {
  background: var(--surface); color: var(--text); box-shadow: var(--shadow);
}

/* En fanerekke inne i en fane — Admin → Oppdatering, med ett system per
   knapp. Den skal leses som et nivå under, ikke som en gjentakelse av rekka
   over: ingen egen innfelt flate, bare en ramme, og litt mindre tekst. Uten
   forskjellen ser de to rekkene like viktige ut, og da er det ikke opplagt
   hvilken av dem som styrer hva. */
.tabs.under {
  background: none; border-color: transparent;
  padding: 0; margin-bottom: 14px; gap: 4px;
}
.tabs.under button { padding: 6px 11px; font-size: .82rem; }
.tabs.under button.on {
  background: var(--surface-2); color: var(--text);
  box-shadow: none; border: 1px solid var(--border);
  /* Ramma legger til to piksler; ta dem fra polstringen, ellers hopper
     knappen i rekka i det den blir valgt. */
  padding: 5px 10px;
}

/* En merkelapp foran knappene i en underrekke — Admin → System →
   Oppdatering, der systemrada står rett under administrasjonens egen
   underfanerekke. To like rekker oppå hverandre leses som én lang rekke;
   ordet foran sier hvilken akse den nederste er. */
.tabs.under .fanemerke {
  display: inline-flex; align-items: center; white-space: nowrap;
  padding: 0 9px 0 3px; font-size: .78rem; color: var(--faint);
}

/* En fanerekke som er lengre enn skjermen — verktøysidens seksten kategorier.
   Rulleskrået er ikke pynt: `.tabs` skjuler rullefeltet, så uten et hint
   finnes det ingenting som sier at rekka fortsetter, og med mus finnes det
   heller ingenting å dra i. Klassene settes fra app.js, som også lar hjulet
   rulle rekka vannrett. Rekkene med tre-fire faner får dem aldri. */
.tabs.rull-start {
  -webkit-mask-image: linear-gradient(to right, transparent, #000 34px);
  mask-image: linear-gradient(to right, transparent, #000 34px);
}
.tabs.rull-slutt {
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 34px), transparent);
  mask-image: linear-gradient(to right, #000 calc(100% - 34px), transparent);
}
.tabs.rull-start.rull-slutt {
  -webkit-mask-image: linear-gradient(to right,
    transparent, #000 34px, #000 calc(100% - 34px), transparent);
  mask-image: linear-gradient(to right,
    transparent, #000 34px, #000 calc(100% - 34px), transparent);
}

/* ============================ Tabell ============================ */

.tbl-wrap { overflow-x: auto; margin: 0 -20px; padding: 0 20px; }
table.tbl { width: 100%; border-collapse: collapse; font-size: .88rem; }
table.tbl th {
  text-align: left; font-size: .74rem; font-weight: 640; letter-spacing: .05em;
  text-transform: uppercase; color: var(--faint);
  padding: 0 12px 9px; border-bottom: 1px solid var(--border); white-space: nowrap;
}
table.tbl td { padding: 11px 12px; border-bottom: 1px solid var(--border); vertical-align: middle; }
table.tbl tr:last-child td { border-bottom: none; }
table.tbl tbody tr:hover { background: var(--surface-2); }
table.tbl td.right, table.tbl th.right { text-align: right; }
table.tbl td.num { font-variant-numeric: tabular-nums; }

/* ============================ Modal ============================ */

.overlay {
  position: fixed; inset: 0; z-index: 80;
  display: grid; place-items: center; padding: 20px;
  background: rgba(0, 0, 0, .5);
  backdrop-filter: blur(3px);
  animation: fade .18s var(--ease);
}
@keyframes fade { from { opacity: 0; } }
.modal {
  width: 100%; max-width: 520px; max-height: min(86vh, 760px);
  /* `min-width: 0` er ikke pynt — det er sperren mot at ett stivt barn drar
     hele vinduet ut av skjermen. Vinduet er et rutenettsbarn, og et slikt
     barn har `min-width: auto`: det nekter å bli smalere enn innholdet sitt,
     helt opp til `max-width`. På en telefon på 390 px betyr det at et felt
     som ikke krymper — nettleserens eget `input[type=file]`, som Safari
     tegner bredt der Chrome tegner det smalt — blåser vinduet opp til 520 px
     og skyver knappene ut over høyrekanten. Målt: 350 px uten, 502 px med et
     barn på 460 px, og 350 px igjen med denne linja.
     Innhold som likevel er for bredt flyter nå *inne i* vinduet i stedet for
     å ta vinduet med seg. */
  min-width: 0;
  display: flex; flex-direction: column;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-xl); box-shadow: var(--shadow-lg);
  animation: rise .22s var(--ease);
}
.modal.wide { max-width: 680px; }
/* Forhåndsvisning av et dokument. Bredere og høyere enn de andre vinduene
   fordi den viser et helt papir og ikke et skjema — en A4-side i 520 px er
   ikke en forhåndsvisning, det er et frimerke. */
.modal.stor { max-width: min(1040px, 94vw); height: min(88vh, 900px); max-height: none; }
.modal.stor .modal-body { padding: 0; display: flex; flex-direction: column; }
.dok-vis {
  flex: 1; min-height: 0; display: flex; align-items: center;
  justify-content: center; background: var(--surface-2); overflow: auto;
}
.dok-vis img { max-width: 100%; max-height: 100%; object-fit: contain; display: block; }
.dok-vis iframe { width: 100%; height: 100%; border: 0; display: block; background: #fff; }
/* Teksten ut av et Word- eller OpenDocument-dokument. Ikke en gjengivelse av
   dokumentet — se app/dokumentlesing.py — så den settes som lesbar tekst i
   en spalte, ikke som en etterligning av et ark. */
.dok-tekst {
  align-items: stretch; padding: 28px; overflow-y: auto;
  background: var(--surface); display: block;
}
.dok-tekst .innhold {
  max-width: 68ch; margin: 0 auto; font-size: .92rem; line-height: 1.65;
  white-space: pre-wrap; overflow-wrap: anywhere;
}
.dok-tekst .innhold p { margin: 0 0 .55em; min-height: .55em; }
.dok-tekst table { border-collapse: collapse; font-size: .86rem; margin: 0 auto; }
.dok-tekst td {
  border: 1px solid var(--border); padding: 5px 9px;
  white-space: pre-wrap; vertical-align: top;
}
/* ------------------------------------------------------------- saker
   En sak er en gruppe du folder ut, ikke en underside. `<details>` og ikke
   en egen tilstand i JS: nettleseren husker åpen/lukket selv, og en side
   med tre saker skal ikke trenge en tilstandsmaskin for å åpne den ene. */
.sak {
  border: 1px solid var(--border); border-radius: var(--r-lg);
  background: var(--surface-2); margin-bottom: 10px; overflow: hidden;
}
.sak[open] { border-color: var(--accent-soft); }
.sak summary {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 14px; cursor: pointer; list-style: none;
}
.sak summary::-webkit-details-marker { display: none; }
.sak summary:hover { background: var(--surface); }
.sak summary .name { font-weight: 600; font-size: .94rem; }
.sak summary .mail { font-size: .8rem; color: var(--muted); }
.sak summary svg { transition: transform .18s var(--ease); flex: none; }
.sak[open] summary svg { transform: rotate(180deg); }
.sak-innhold {
  padding: 4px 14px 14px; border-top: 1px solid var(--border);
  background: var(--surface);
}
.sak-innhold .rows { margin-top: 8px; }
.sak-innhold > .hint { margin: 10px 0 0; }

.dok-tomt {
  display: flex; flex-direction: column; align-items: center; gap: 12px;
  color: var(--muted); font-size: .9rem; text-align: center;
  padding: 40px 24px; margin: auto; max-width: 42ch;
}
@keyframes rise { from { opacity: 0; transform: translateY(14px) scale(.985); } }
.modal-head {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 20px 20px 14px; border-bottom: 1px solid var(--border);
}
.modal-head h2 { font-size: 1.05rem; }
.modal-head p { font-size: .84rem; color: var(--muted); margin-top: 3px; }
.modal-body { padding: 18px 20px; overflow-y: auto; flex: 1; }
.modal-foot {
  display: flex; justify-content: flex-end; gap: 8px;
  padding: 14px 20px 18px; border-top: 1px solid var(--border);
}
.modal-foot .left { margin-right: auto; }

/* ============================ Beskjeder ============================ */

.toast-stack {
  position: fixed; left: 50%; bottom: 24px; transform: translateX(-50%);
  z-index: 90; display: flex; flex-direction: column; gap: 8px;
  align-items: center; pointer-events: none;
  padding-bottom: env(safe-area-inset-bottom);
}
.toast {
  display: flex; align-items: center; gap: 9px;
  padding: 11px 17px; border-radius: var(--r-md);
  background: var(--surface); color: var(--text);
  border: 1px solid var(--border); box-shadow: var(--shadow-lg);
  font-size: .89rem; max-width: min(92vw, 440px);
  animation: toastin .22s var(--ease);
}
.toast.out { animation: toastout .22s var(--ease) forwards; }
.toast.ok .ico { color: var(--ok); }
.toast.bad .ico { color: var(--danger); }
@keyframes toastin { from { opacity: 0; transform: translateY(12px); } }
@keyframes toastout { to { opacity: 0; transform: translateY(8px); } }

.notice {
  display: flex; gap: 10px; align-items: flex-start;
  padding: 12px 14px; border-radius: var(--r-md);
  font-size: .85rem; line-height: 1.5;
  background: var(--surface-2); border: 1px solid var(--border); color: var(--muted);
}
.notice .ico { margin-top: 1px; flex: none; }
.notice.warn { background: var(--warn-soft); border-color: transparent; color: var(--warn); }
.notice.bad { background: var(--danger-soft); border-color: transparent; color: var(--danger); }
.notice.accent { background: var(--accent-soft); border-color: transparent; color: var(--accent); }
.notice.ok { background: var(--ok-soft); border-color: transparent; color: var(--ok); }
.notice strong { color: inherit; font-weight: 640; }

/* Lista i selskapsvinduet over hva en integrasjon gir deg. Ikke en `.rows`:
   det er en oppregning å lese, ikke rader å handle på. */
.punkt { list-style: none; margin: 8px 0 0; padding: 0; display: grid; gap: 7px; }
.punkt li {
  display: flex; align-items: center; gap: 9px;
  font-size: .88rem; color: var(--muted);
}
.punkt li .ico { color: var(--accent); flex: none; }

/* Et varsel med en knapp i seg. Egen klasse og ikke en regel på `.notice`:
   slås ombrytning på for alle, får et vanlig varsel med lang tekst ikonet
   alene på første linje og teksten på den neste — en flexboks uten wrap
   krymper teksten, en med wrap flytter den. Her skal teksten krympe og
   *knappen* flytte, så under 560 px tar knappen hele bredden og faller ned
   på egen linje i stedet for å presse tekstspalta ned mot 140 px. */
.notice.knapp { flex-wrap: wrap; }
.notice.knapp > span { min-width: 0; flex: 1 1 150px; }
@media (max-width: 560px) {
  .notice.knapp .btn { width: 100%; justify-content: center; }
}

.err-text { color: var(--danger); font-size: .85rem; min-height: 1.2em; margin-top: 10px; }

/* ============================ Innlogging ============================ */

/* Innlogging, godkjenning og «nytt passord» deler ett skall: et fotografi
   som fyller skjermen, teksten i den ene enden og kortet i den andre.

   Bildet ligger bak *begge* spaltene, ikke bare den venstre. Det er derfor
   bakgrunnen står på .auth-wrap og ikke på .auth-scene: de fire bildene er
   komponert med motivet til venstre og tom himmel til høyre, og deler man
   dem i to spalter med hver sin bakgrunn, ryker nettopp den komposisjonen.

   Hvilket bilde som vises settes som klasse fra tidsbolk() i app.js. Bare
   den ene fila hentes — nettleseren laster ikke en background-image den
   ikke bruker.

   Tekstfargen følger bildet, ikke temaet. Et tema kan være mørkt mens
   bildet er en morgenhimmel, og lys tekst på lys himmel er uleselig
   uansett hvor riktig den er i forhold til temaet. */

.auth-wrap {
  flex: 1;
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1.06fr) minmax(0, .94fr);
  align-items: stretch;
  min-height: 100%;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;

  /* Lys tekst er standarden — natt og kveld. Morgen og dag snur den under. */
  --scene-tekst: #f4f8fc;
  --scene-svak: rgba(244, 248, 252, .8);
  --scene-chip: rgba(255, 255, 255, .17);
  --scene-slor: rgba(5, 11, 18, .74);
}

/* Bakgrunnsfargen er bildets egen snittfarge. Den står i det halve sekundet
   fila lastes, så siden ikke blinker svart under en morgenhimmel. */
.auth-wrap.bg-natt { background-color: #0c1f25; background-image: url("/static/bakgrunn/natt.jpg"); }
.auth-wrap.bg-morgen { background-color: #c3b39a; background-image: url("/static/bakgrunn/morgen.jpg"); }
.auth-wrap.bg-dag { background-color: #9ec7e5; background-image: url("/static/bakgrunn/dag.jpg"); }
.auth-wrap.bg-kveld { background-color: #876d7a; background-image: url("/static/bakgrunn/kveld.jpg"); }
/* Julebildet tar de mørke timene i desember — se erJul() i app.js.

   Det er det eneste bildet med et motiv som *må* være med i utsnittet: et
   juletre og en lykt nede til venstre. De tre andre er landskap som tåler å
   bli beskåret hvor som helst. Derfor to avvik fra resten, begge med samme
   grunn:

   Utsnittet forankres til venstre kant i stedet for midten. Midtstilt
   beskjæres treet vekk — på 1440 px forsvinner 80 piksler i hver ende, og
   det er akkurat treet; det som blir igjen er en stripe lys langs kanten.
   Det som ryker i den andre enden er tomt vann.

   Og sløret er lettere her enn ellers. Det er sterkest langs venstre kant,
   altså nøyaktig der treet og lykta står, og på .74 slukket det dem. Den
   dype nattehimmelen bak teksten trenger det ikke: kontrasten er målt til
   10,5:1 på det svakeste med .55. */
.auth-wrap.bg-jul {
  background-color: #2a404c;
  background-image: url("/static/bakgrunn/jul.jpg");
  --scene-slor: rgba(5, 11, 18, .55);
}
/* Samme sted i dagslys. Lyst bilde, så mørk tekst — det er lysheten i bildet
   som avgjør, ikke at det er jul. */
.auth-wrap.bg-jul-dag {
  background-color: #aa988e;
  background-image: url("/static/bakgrunn/jul-dag.jpg");
}

/* Påsken tar de lyse timene — morgen og dag. Kveld og natt går som ellers:
   det finnes bare ett påskebilde, og det er en soloppgang. Den samme
   soloppgangen klokka elleve om kvelden ville vært en feil, ikke en påske. */
.auth-wrap.bg-paske {
  background-color: #ccbdac;
  background-image: url("/static/bakgrunn/paske.jpg");
}

/* Høytidsbildene har et motiv i venstre kant som må være med — juletreet og
   lykta, påskeeggene og påskeliljene. De fire vanlige er landskap som tåler
   å bli beskåret hvor som helst, og står midtstilt. Her forankres utsnittet
   til venstre kant i stedet: på en telefon beskjæres 1226 piksler i bredden,
   og midtstilt er det nøyaktig motivet som forsvinner. Det som ryker i den
   andre enden er tomt vann. */
.auth-wrap.bg-jul,
.auth-wrap.bg-jul-dag,
.auth-wrap.bg-paske { background-position: 0% center; }

/* Teksten flyttes opp mot himmelen på julebildene — juletreet er høyt, og
   midtstilt havner overskriften oppå det. Da taper begge to: lysene blir
   bakgrunnsstøy og overskriften blir flekkete. Påskebildet trenger det ikke,
   for der ligger motivet lavt — eggene står nede ved vannkanten, godt under
   teksten. */
.auth-wrap.bg-jul .auth-scene, .auth-wrap.bg-jul-dag .auth-scene {
  justify-content: flex-start;
  padding-top: clamp(40px, 8vh, 96px);
}

/* De to lyse bildene. Målt lyshet i tekstfeltet er 209 og 211 av 255 — der
   er hvit tekst borte uansett hvor kraftig sløret er. */
.auth-wrap.bg-morgen, .auth-wrap.bg-dag, .auth-wrap.bg-jul-dag,
.auth-wrap.bg-paske {
  --scene-tekst: #14202a;
  --scene-svak: rgba(20, 32, 42, .78);
  --scene-chip: rgba(255, 255, 255, .5);
  --scene-slor: rgba(255, 255, 255, .66);
}

/* Sløret som bærer teksten. Det ligger bare over den enden teksten står i og
   toner ut på midten, slik at høyre halvdel av fotografiet står urørt. */
.auth-wrap::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: linear-gradient(100deg, var(--scene-slor) 0%,
              color-mix(in srgb, var(--scene-slor) 45%, transparent) 30%,
              transparent 62%);
}

.auth-scene {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(34px, 3.6vw, 64px);
}

.auth-form {
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  padding: clamp(24px, 4vw, 48px);
}

.auth-card {
  width: 100%; max-width: 396px; padding: 30px 28px;
  box-shadow: var(--shadow-lg);
}
.auth-logo {
  width: 52px; height: 52px; border-radius: 16px; margin: 0 auto 16px;
  display: grid; place-items: center;
  background: var(--accent-soft); color: var(--accent);
}
.auth-card h1 { font-size: 1.42rem; text-align: center; }
.auth-card .sub { text-align: center; color: var(--muted); font-size: .89rem; margin: 5px 0 22px; }
.auth-tabs {
  display: flex; gap: 3px; padding: 3px; margin-bottom: 18px;
  background: var(--surface-inset); border: 1px solid var(--border); border-radius: var(--r-md);
}
.auth-tabs button {
  flex: 1; padding: 8px; border-radius: var(--r-sm);
  font-size: .87rem; font-weight: 590; color: var(--muted);
}
.auth-tabs button.on { background: var(--surface); color: var(--text); box-shadow: var(--shadow); }

/* ---- teksten over bildet ---- */

.scene-tekst { max-width: 30rem; color: var(--scene-tekst); }
.scene-tittel {
  font-size: clamp(1.7rem, 2.9vw, 2.5rem);
  font-weight: 680;
  line-height: 1.15;
  letter-spacing: -.02em;
  text-wrap: balance;
}
.scene-sub {
  margin-top: 12px;
  color: var(--scene-svak);
  font-size: clamp(.92rem, 1.1vw, 1rem);
  line-height: 1.55;
  max-width: 26rem;
}
.scene-punkter { list-style: none; margin-top: 26px; display: grid; gap: 11px; }
.scene-punkter li {
  display: flex; align-items: center; gap: 11px;
  font-size: .9rem; color: var(--scene-tekst);
}
/* Ikonene er i tekstfargen, ikke i aksentfargen. Aksenten følger temaet, og
   portalens turkis oppå en gyllen kveldshimmel er to farger som krangler. */
.scene-punkter .ico {
  color: var(--scene-tekst);
  padding: 7px;
  border-radius: var(--r-sm);
  background: var(--scene-chip);
  box-sizing: content-box;
}

/* Under 960 px er det ikke plass til to spalter. Fotografiet blir bakteppe
   for hele siden, teksten i det skrus av — kortet har merket og overskriften
   fra før, og to overskrifter oppå hverandre er verre enn ingen scenetekst.
   Utsnittet flyttes mot venstre så fjellene kommer med: et liggende bilde
   beskåret på midten i et stående vindu viser bare tom himmel. */
@media (max-width: 960px) {
  .auth-wrap {
    grid-template-columns: 1fr;
    background-position: 32% center;
  }
  .auth-wrap::before {
    background: linear-gradient(to bottom,
      color-mix(in srgb, var(--scene-slor) 55%, transparent) 0%,
      color-mix(in srgb, var(--scene-slor) 25%, transparent) 100%);
  }
  .auth-scene { display: none; }
  .auth-card {
    background: color-mix(in srgb, var(--surface) 88%, transparent);
    backdrop-filter: saturate(160%) blur(16px);
    -webkit-backdrop-filter: saturate(160%) blur(16px);
  }
}

/* ============================ Veiviser ============================ */

.onb-wrap { flex: 1; display: grid; place-items: center; padding: 24px; }
.onb-card { width: 100%; max-width: 580px; padding: 30px 30px 26px; }
.onb-steps { display: flex; gap: 5px; margin-bottom: 24px; }
.onb-steps span { flex: 1; height: 4px; border-radius: var(--r-pill); background: var(--border); transition: background .3s var(--ease); }
.onb-steps span.on { background: var(--accent); }
.onb-card h1 { font-size: 1.4rem; }
.onb-card .sub { color: var(--muted); font-size: .9rem; margin: 6px 0 20px; line-height: 1.5; }
.onb-nav { display: flex; justify-content: space-between; align-items: center; gap: 10px; margin-top: 24px; }

.pick-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 9px; }
.pick {
  display: flex; gap: 11px; align-items: flex-start; text-align: left;
  padding: 13px; border-radius: var(--r-md);
  border: 1.5px solid var(--border); background: transparent; color: var(--text);
  transition: border-color .15s, background .15s;
}
.pick:hover { border-color: var(--border-strong); }
.pick.on { border-color: var(--accent); background: var(--accent-soft); }
.pick .p-ico {
  width: 32px; height: 32px; border-radius: 9px; flex: none;
  display: grid; place-items: center;
  background: var(--surface-2); color: var(--muted);
}
.pick.on .p-ico { background: var(--accent); color: var(--accent-contrast); }
.pick h4 { font-size: .89rem; }
.pick p { font-size: .75rem; color: var(--muted); margin-top: 2px; line-height: 1.35; }
.pick .tick { margin-left: auto; color: var(--accent); opacity: 0; transition: opacity .15s; }
.pick.on .tick { opacity: 1; }

/* Temavelger */
.theme-swiper { position: relative; }
.theme-track {
  display: flex; gap: 12px; overflow-x: auto; scroll-snap-type: x mandatory;
  padding: 4px 2px 12px; scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.theme-track::-webkit-scrollbar { display: none; }
.theme-slide {
  flex: 0 0 78%; scroll-snap-align: center; border-radius: var(--r-lg);
  border: 2px solid var(--border); overflow: hidden; padding: 0;
  text-align: left; color: var(--text); background: var(--surface);
  transition: border-color .16s;
}
.theme-slide.on { border-color: var(--accent); }
.theme-preview { height: 128px; position: relative; background: var(--bg); }
.theme-preview .pv { position: absolute; border-radius: 7px; }
.theme-slide .theme-info { padding: 11px 13px; border-top: 1px solid var(--border); }
.theme-slide .theme-info h4 { font-size: .93rem; display: flex; align-items: center; gap: 7px; }
.theme-slide .theme-info p { font-size: .78rem; color: var(--muted); margin-top: 2px; }
.theme-dots { display: flex; justify-content: center; gap: 6px; }
.theme-dots span { width: 6px; height: 6px; border-radius: 50%; background: var(--border-strong); transition: background .2s, width .2s var(--ease); }
.theme-dots span.on { background: var(--accent); width: 18px; border-radius: var(--r-pill); }

/* 180px, ikke 148: med 148 fikk en telefon to spalter der navnet ikke gikk
   inn, og temaene het «Nor…» og «Mid…» i velgeren. Nå faller den til én
   spalte i stedet, og navnet står helt. */
.theme-mini-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 9px; }
.theme-mini {
  display: flex; align-items: center; gap: 10px; padding: 10px 12px;
  border-radius: var(--r-md); border: 1.5px solid var(--border);
  background: var(--surface); color: var(--text);
  font-size: .87rem; font-weight: 570; text-align: left;
  transition: border-color .15s;
}
.theme-mini:hover { border-color: var(--border-strong); }
.theme-mini.on { border-color: var(--accent); }
.theme-mini .swatch {
  width: 26px; height: 26px; border-radius: 8px; flex: none;
  border: 1px solid var(--border);
  background: linear-gradient(135deg, var(--accent) 0 50%, var(--accent-2) 50% 100%);
}
.theme-mini .tick { margin-left: auto; color: var(--accent); opacity: 0; }
.theme-mini.on .tick { opacity: 1; }

.choice-col { display: flex; flex-direction: column; gap: 9px; }
.choice-col .btn { justify-content: flex-start; }

/* ============================ Aria ============================ */

.aria-fab {
  position: fixed; right: 22px; bottom: 22px; z-index: 45;
  width: 52px; height: 52px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--accent); color: var(--accent-contrast);
  box-shadow: var(--shadow-lg);
  transition: transform .18s var(--ease);
}
.aria-fab:hover { transform: scale(1.06); }
.aria-fab:active { transform: scale(.97); }

.aria-panel {
  position: fixed; right: 22px; bottom: 86px; z-index: 45;
  width: min(392px, calc(100vw - 44px)); height: min(560px, calc(100vh - 140px));
  display: none; flex-direction: column; overflow: hidden;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-xl); box-shadow: var(--shadow-lg);
}
.aria-panel.open { display: flex; animation: rise .2s var(--ease); }
.aria-head {
  display: flex; align-items: center; gap: 11px;
  padding: 14px 16px; border-bottom: 1px solid var(--border);
}
.aria-head .orb {
  width: 32px; height: 32px; border-radius: 50%; flex: none;
  display: grid; place-items: center;
  background: radial-gradient(circle at 34% 32%, var(--accent-2), var(--accent));
  color: var(--accent-contrast);
}
.aria-head h3 { font-size: .95rem; }
.aria-head p { font-size: .74rem; color: var(--muted); margin-top: 1px; }
.aria-msgs { flex: 1; overflow-y: auto; padding: 16px; display: flex; flex-direction: column; gap: 9px; }
.msg {
  max-width: 86%; padding: 10px 13px; border-radius: var(--r-lg);
  font-size: .89rem; line-height: 1.5; white-space: pre-wrap; word-break: break-word;
}
.msg.user { align-self: flex-end; background: var(--accent); color: var(--accent-contrast); border-bottom-right-radius: 5px; }
.msg.aria { align-self: flex-start; background: var(--surface-2); border: 1px solid var(--border); border-bottom-left-radius: 5px; }
.msg.aria a { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; word-break: break-all; }
/* Et varsel er portalens beskjed om at Aria ikke er tilgjengelig — ikke en
   replikk fra henne. Derfor midtstilt og i --warn i stedet for å ligge til
   venstre som boblene hennes: sto det i en Aria-boble, leses det som noe hun
   har sagt, og det var nettopp den forvekslingen som forvirret samtalen. */
.msg.varsel {
  align-self: center; max-width: 94%; display: flex; gap: 7px;
  align-items: flex-start; font-size: .84rem;
  background: var(--warn-soft); border: 1px solid var(--warn);
  color: var(--text);
}
.msg.varsel svg { flex: none; color: var(--warn); margin-top: 2px; }
.msg.typing { color: var(--muted); display: flex; gap: 4px; align-items: center; }
.msg.typing i { width: 5px; height: 5px; border-radius: 50%; background: currentColor; animation: blink 1.2s infinite; }
.msg.typing i:nth-child(2) { animation-delay: .18s; }
.msg.typing i:nth-child(3) { animation-delay: .36s; }
@keyframes blink { 0%, 60%, 100% { opacity: .28; } 30% { opacity: 1; } }
.aria-inputrow { display: flex; gap: 8px; padding: 12px; border-top: 1px solid var(--border); }
.aria-inputrow input { flex: 1; }
.aria-inputrow .btn { padding: 10px 12px; }

/* ============================ Admin ============================ */

.admin-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(158px, 1fr)); gap: 10px; }
.stat-box {
  padding: 15px 16px; border-radius: var(--r-md);
  background: var(--surface); border: 1px solid var(--border);
}
.stat-box b { display: block; font-size: 1.5rem; font-weight: 690; line-height: 1.15; font-variant-numeric: tabular-nums; }
.stat-box span { font-size: .78rem; color: var(--muted); }

/* Brukerlista. Flyter i én linje når det er plass, brekker til to på
   telefon — uten vannrett rulling, som gjemmer knappen. */
.user-list > .user-row {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 13px 0; border-bottom: 1px solid var(--border);
}
.user-list > .user-row:last-child { border-bottom: none; }
.user-row .who-wrap { display: flex; align-items: center; gap: 11px; flex: 1 1 240px; min-width: 0; }
.user-row .meta {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  font-size: .79rem; color: var(--muted);
}
.user-row .meta span { display: inline-flex; align-items: center; gap: 5px; }
.user-row .acts { margin-left: auto; }

@media (max-width: 620px) {
  /* Navn → nøkkeltall → handling. Knappen sist, der tommelen er. */
  .user-row .meta { order: 3; flex-basis: 100%; gap: 12px; }
  .user-row .acts { order: 4; flex-basis: 100%; margin-left: 0; }
  .user-row .acts .btn { width: 100%; }
}

/* Én linje per modul: navnet til venstre, nivåvelgeren til høyre, og et
   tannhjul helt ytterst til adressene, testen og koblingen.

   Blokka som sto her før var fem rader høy ganger tjuefire moduler, og fire
   av de fem svarte på noe man spør om én gang per tjeneste. Nivået er det
   man faktisk gjør her, så det er det ene som står framme. */
.modul-rad {
  display: flex; align-items: center; gap: 10px;
  padding: 7px 0; border-bottom: 1px solid var(--border);
}
.modul-rad:last-of-type { border-bottom: none; }
.modul-navn {
  display: flex; align-items: center; gap: 9px; min-width: 0;
  font-size: .94rem; font-weight: 600; margin-right: auto;
}
/* Navnet er det ene som får lov til å vike. Uten den viker nivåvelgeren
   i stedet, og da er knappene ulikt brede fra rad til rad. */
.modul-navn .truncate { min-width: 0; }
.modul-rad .dot { flex: none; }
.modul-rad .badge { flex: none; margin-left: 0; }
.modul-rad .nivaa-velger { flex: none; }

/* Kvitteringen på en autolagring. Plassen står uansett, så knapperekka ikke
   flytter seg sidelengs i det hakket legger seg — en rad som hopper under
   fingeren er en rad man trykker feil på neste gang. */
.lagret-merke {
  flex: none; display: inline-flex; align-items: center; gap: 5px;
  width: 20px; justify-content: center; font-size: .78rem;
  opacity: 0; transition: opacity .18s;
}
.lagret-merke.vis { opacity: 1; }
.lagret-merke.ok { color: var(--ok); }
.lagret-merke.bad { color: var(--danger); width: auto; }

/* Kalkulatorene har ingen adresse og derfor intet tannhjul. Plassen holdes
   av, så de to listene står på linje med hverandre. */
.tannhjul-plass { flex: none; width: 34px; }

.modul-adresse { display: flex; gap: 8px; align-items: center; }
.modul-adresse input { flex: 1; min-width: 0; }
.res.ok { color: var(--ok); }
.res.bad { color: var(--danger); }
/* Bare i modulvinduet. `.res` brukes også som en mellomromsholder ved siden
   av en testknapp andre steder, og der skal en tom rad beholde plassen sin. */
[data-felt] > .res:empty { display: none; }

/* Koblingen inne i modulvinduet: prikken sier om adresse og nøkkel er satt,
   uten at knappen må bytte tekst. */
.modul-kobling {
  display: flex; align-items: center; gap: 10px;
  padding: 12px; border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--surface-2); font-size: .86rem;
}
.modul-kobling .dot { flex: none; }

/* Fire nivåer på rad: skjult → kun system → beta → alle. Én knapp er på, og
   fargen sier hvor langt ut modulen er sluppet — grå inne, gul underveis,
   grønn i drift. Det er raskere å lese enn fire like knapper med tekst. */
.nivaa-velger { display: flex; gap: 0; }
.nivaa-velger button {
  border: 1px solid var(--border); background: var(--surface-2); color: var(--muted);
  font: inherit; font-size: .78rem; font-weight: 560; padding: 6px 12px; cursor: pointer;
  border-right-width: 0;
}
.nivaa-velger button:first-child { border-radius: var(--r-sm) 0 0 var(--r-sm); }
.nivaa-velger button:last-child { border-radius: 0 var(--r-sm) var(--r-sm) 0; border-right-width: 1px; }
.nivaa-velger button:hover { color: var(--text); }
.nivaa-velger button.on { color: var(--text); background: var(--surface); box-shadow: inset 0 0 0 1px var(--border); }
.nivaa-velger button.on.skjult { background: var(--surface-2); color: var(--faint); box-shadow: inset 0 0 0 2px var(--border-strong); text-decoration: line-through; }
.nivaa-velger button.on.system { background: var(--surface-2); color: var(--muted); box-shadow: inset 0 0 0 2px var(--faint); }
.nivaa-velger button.on.beta { background: var(--warn-soft); color: var(--warn); border-color: transparent; }
.nivaa-velger button.on.alle { background: var(--ok-soft); color: var(--ok); border-color: transparent; }

/* ============================ Verktøy ============================ */

/* Ramma rundt en kopiert verktøyside. Høyden er bundet til vindushøyden og
   ikke til innholdet: en iframe kan ikke måle seg selv på tvers av
   dokumenter uten at siden inni sier fra, og de fem sidene er kopiert
   urørt — de vet ikke at de står i en ramme. En fast, romslig høyde med
   egen rulling er ærligere enn en høyde som hopper. */
.vk-ramme {
  border: 1px solid var(--border); border-radius: var(--r-lg);
  overflow: hidden; background: var(--surface); box-shadow: var(--shadow);
}
.vk-ramme iframe {
  display: block; width: 100%; height: min(78vh, 900px); border: 0;
}

.tilbake {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: .82rem; color: var(--muted); margin-bottom: 8px;
}
.tilbake:hover { color: var(--accent); }

/* Kalkulatorene: skjema til venstre, svaret til høyre. Svaret følger med
   nedover på store skjermer — endrer du et tall langt nede i skjemaet, skal
   du se hva det gjorde uten å rulle opp igjen. */
.vk-layout {
  display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 4fr);
  gap: 14px; align-items: start;
}
.vk-ut { position: sticky; top: 78px; }
@media (max-width: 900px) {
  .vk-layout { grid-template-columns: 1fr; }
  .vk-ut { position: static; }
}

/* Tannhjulet og sammendraget over kalkulatoren. De står inntil hverandre og
   ikke i hver sin ende, fordi de er én ting: lista sier hva tallene bak
   knappen står på.

   Den brytes, og det var et valg tatt om. Først lå den på én linje som rullet
   vannrett, og på en telefon sto det «… 8 ‹» — halve sammendraget usynlig, og
   uten rullefelt heller ingenting som sa at det fortsatte. Et sammendrag som
   ikke kan leses er verre enn ingen linje: da tror man at man har lest det. */
.vk-topp {
  display: flex; align-items: center; justify-content: flex-end;
  gap: 10px; margin: -2px 0 12px;
}
/* `--muted` og ikke `--faint`, som ellers er fargen på småtekst her. Linja
   er ikke en bildetekst, den er de eneste tallene som er igjen å lese når
   feltene er ryddet bort — og `--faint` mot bakgrunnen er 2,8:1 i Daggry og
   2,5:1 i Fjord. `--muted` er 4,8 og 4,4. De lyse temaene er der
   kontrastfeilene dukker opp. */
.vk-oppsummering {
  margin: 0; min-width: 0; font-size: .76rem; color: var(--muted);
  font-variant-numeric: tabular-nums; text-align: right; line-height: 1.5;
}
@media (max-width: 700px) {
  .vk-topp { justify-content: space-between; align-items: flex-start; }
  .vk-oppsummering { text-align: left; }
}

/* Feltene som ligger bak tannhjulet. De står i dokumentet hele tiden — det
   er vinduet som låner boksen — så den må kunne skjules. `display: grid`
   under slår nettleserens egen `hidden`-regel, og uten linja her sto åtte
   felter igjen midt i kalkulatoren. Samme felle som `.field[hidden]` lenger
   opp i fila. */
.vk-oppsett[hidden] { display: none; }
.vk-oppsett { display: grid; grid-template-columns: 1fr 1fr; gap: 0 14px; }
.vk-oppsett > .vk-skille { grid-column: 1 / -1; }
.vk-oppsett > .vk-skille:first-child { margin-top: 2px; }
@media (max-width: 520px) {
  .vk-oppsett { grid-template-columns: 1fr; }
}

.vk-hoved { text-align: center; padding: 4px 0 16px; }
.vk-h-tall {
  display: block; font-size: clamp(2rem, 6vw, 2.8rem); font-weight: 700;
  letter-spacing: -.02em; line-height: 1.05; color: var(--accent);
  font-variant-numeric: tabular-nums;
}
.vk-h-tall em { font-size: .42em; font-style: normal; font-weight: 600; color: var(--muted); }
.vk-x { color: var(--muted); margin: 0 .12em; font-weight: 500; }
.vk-h-tekst {
  display: block; margin-top: 4px; font-size: .82rem; color: var(--muted);
  text-transform: uppercase; letter-spacing: .06em; font-weight: 620;
}
.vk-h-hint { display: block; margin-top: 5px; font-size: .8rem; color: var(--faint); }

.vk-rad {
  display: flex; align-items: baseline; justify-content: space-between; gap: 14px;
  padding: 9px 0; border-top: 1px solid var(--border); font-size: .87rem;
}
.vk-rad > span { color: var(--muted); }
.vk-rad > span em { font-style: normal; font-size: .82em; }
.vk-rad > b { font-variant-numeric: tabular-nums; white-space: nowrap; }
.vk-rad.sterk > b { color: var(--accent); font-size: 1.02rem; }
.vk-rad .badge { margin-left: 7px; }

.vk-skille {
  margin: 18px 0 2px; font-size: .74rem; font-weight: 640;
  letter-spacing: .06em; text-transform: uppercase; color: var(--faint);
}

/* Figurene i svarkortet. `vk-graf` strekkes til å fylle bredden, så den skal
   aldri inneholde tekst — bokstavene ville blitt strukket med. Etikettene
   ligger i `vk-akse` under. `vk-tegning` beholder forholdet og kan ha tekst. */
.vk-graf { display: block; margin-top: 8px; overflow: visible; }
.vk-tegning { display: block; margin-top: 8px; width: 100%; height: auto; }
.vk-akse {
  display: flex; justify-content: space-between; gap: 10px;
  margin-top: 3px; font-size: .72rem; color: var(--faint);
  font-variant-numeric: tabular-nums;
}
.vk-figurtekst {
  margin: 7px 0 0; font-size: .76rem; line-height: 1.5; color: var(--muted);
}

/* Tegnforklaringen under en stablet stolpe. Fargeprikken alene holder ikke —
   `--accent` og `--accent-2` ligger tett i flere temaer — så navnet og
   prosenten står ved siden av hver prikk og ikke bare i figuren. */
.vk-stolpetegn {
  display: flex; flex-wrap: wrap; gap: 4px 14px; margin-top: 7px;
  font-size: .72rem; color: var(--muted);
}
.vk-stolpetegn span { display: inline-flex; align-items: center; gap: 5px; }
.vk-stolpetegn i {
  width: 9px; height: 9px; border-radius: 2px; flex: none;
  border: 1px solid var(--border);
}
/* Samme skravur som i stolpen. Uten den ville tegnforklaringen vist to like
   fargeprikker for to felter figuren skiller på form. */
.vk-stolpetegn i.skrav {
  background-image: repeating-linear-gradient(45deg,
    transparent 0 2px, var(--bg) 2px 4px);
}

/* PID-simulatoren. Den er ikke et skjema med et svar, men en sløyfe som
   kjører, så den bryter med `vk-layout` øverst: skinna og grafene skal ha
   hele bredden, og skjemaet kommer under.

   Gliderne er stilt for hånd fordi `input[type=range]` ikke arver noe som
   helst fra resten av skjemaelementene — uten reglene under står de i
   nettleserens egen blåfarge, lik i alle seks temaene. */
.pid-verktoy > .card + .card,
.pid-verktoy > .card + .vk-layout { margin-top: 14px; }

/* Et fanepanel inne i et verktøy. Kortene i det står i samme rekke som de
   som ligger rett under `.pid-verktoy`, så de skal ha de samme avstandene —
   uten reglene her klistrer de seg sammen i det de flytter én nivå ned.

   Panelet får *ingen* `display`, med vilje: det skjules med `hidden`, og en
   `display` på klassen ville vunnet over den og latt alle tre fanene stå
   under hverandre. */
.pid-verktoy > .card + .tabs { margin-top: 14px; }
.vk-fane > .card + .card,
.vk-fane > .card + .vk-layout,
.vk-fane > .vk-layout + .card { margin-top: 14px; }

/* Summen under dellista i pumpeverktøyet. ΣK er det ene tallet av de
   fjorten radene som går videre inn i regnestykket, så den står som et tall
   og ikke som enda en rad. */
.pu-sumk {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--border);
}
.pu-sumk span { font-size: .82rem; color: var(--muted); }
.pu-sumk b { font-size: 1.15rem; font-variant-numeric: tabular-nums; }
.pu-sumk em { font-style: normal; font-size: .78rem; color: var(--faint); }

.pid-linje { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.pid-valg {
  background: var(--surface-inset); color: var(--muted); cursor: pointer;
  border: 1px solid var(--border); border-radius: var(--r-sm);
  padding: 6px 12px; font-size: .84rem; font-weight: 600; font-family: inherit;
}
.pid-valg:hover { color: var(--text); border-color: var(--border-strong); }
.pid-valg.on {
  background: var(--accent-soft); color: var(--accent);
  border-color: var(--accent);
}

.pid-sprang {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: .82rem; color: var(--muted);
}
.pid-sprang select { width: auto; padding: 6px 26px 6px 10px; font-size: .84rem; }

/* Skinna: måleverdien som en kule, settpunktet som en flaggstang. To
   former og ikke to farger, fordi de to står oppå hverandre nettopp når
   sløyfa har lyktes — og en kule som dekker en rombe ser ut som at
   settpunktet er borte. Stanga stikker opp over kula og synes uansett. */
.pid-skinne { margin-bottom: 4px; }
.pid-rail {
  position: relative; height: 40px; margin: 4px 11px 0;
}
.pid-rail::before {
  content: ''; position: absolute; left: 0; right: 0; top: 27px; height: 2px;
  border-radius: 1px; background: var(--border-strong);
}
.pid-rail::after {
  content: ''; position: absolute; left: 0; right: 0; top: 22px; height: 12px;
  background-image: repeating-linear-gradient(to right,
    var(--border) 0 1px, transparent 1px 12.5%);
}
.pid-ball {
  position: absolute; top: 19px; width: 18px; height: 18px; border-radius: 50%;
  background: var(--accent); transform: translateX(-50%); z-index: 2;
  box-shadow: 0 0 0 3px var(--surface);
}
/* Settpunktet er nøytralt og ikke `--warn`. I Daggry er `--accent` #d96a2b
   og `--warn` #b45309 — to oransjetoner som ikke lar seg skille på en
   strek. Måleverdien er den som skal ha merkefargen; settpunktet er en
   referanse, og en referanse i tekstfargen er tydelig i alle sju temaene. */
.pid-mal {
  position: absolute; top: 4px; width: 2px; height: 30px; z-index: 3;
  background: var(--text); transform: translateX(-50%);
}
.pid-mal > i {
  position: absolute; top: -5px; left: 1px; width: 9px; height: 9px;
  background: var(--text); transform: translate(-50%, 0) rotate(45deg);
}
.pid-rail-tekst {
  display: flex; justify-content: space-between;
  font-size: .72rem; color: var(--faint);
}


.pid-tall {
  display: flex; flex-wrap: wrap; gap: 10px 26px; margin-top: 6px;
}
.pid-tall > div { display: flex; align-items: baseline; gap: 5px; }
.pid-tall b {
  font-size: 1.35rem; font-weight: 700; font-variant-numeric: tabular-nums;
  letter-spacing: -.01em;
}
.pid-tall em { font-style: normal; font-size: .8rem; color: var(--muted); }
.pid-t-etikett {
  font-size: .7rem; text-transform: uppercase; letter-spacing: .06em;
  color: var(--faint); font-weight: 640; margin-right: 3px;
}

/* Tre bidrag med hvert sitt spor, og et nullpunkt midt i sporet: fortegnet
   er halve poenget — et D-ledd som drar tilbake ser man bare hvis det får
   gå til venstre. */
.pid-bidrag { display: grid; gap: 9px; margin-top: 16px; }
.pid-b-topp {
  display: flex; align-items: baseline; gap: 8px; font-size: .8rem;
  margin-bottom: 4px;
}
.pid-b-topp b { color: var(--accent); font-weight: 700; width: 14px; }
.pid-b-topp span { color: var(--muted); flex: 1; min-width: 0; }
.pid-b-topp i {
  font-style: normal; font-variant-numeric: tabular-nums; font-weight: 640;
  white-space: nowrap;
}
.pid-b-spor {
  position: relative; height: 8px; border-radius: 4px;
  background: var(--surface-inset); border: 1px solid var(--border);
}
.pid-b-spor::before {
  content: ''; position: absolute; left: 50%; top: -2px; bottom: -2px;
  width: 1px; background: var(--border-strong);
}
.pid-b-spor > span {
  position: absolute; top: 1px; bottom: 1px; border-radius: 3px;
  background: var(--accent); min-width: 0;
}

/* Aksetallene står i HTML og ikke i SVG-en. Grafen strekkes til bredden
   med `preserveAspectRatio="none"`, og da dras teksten like mye som kurven
   — «100» blir et bredt «100» som ikke ligner resten av appen. */
.pid-graf { display: grid; gap: 16px; margin-top: 6px; }
.pid-g-rad { display: grid; grid-template-columns: 52px minmax(0, 1fr); gap: 6px; }
.pid-g-akse {
  display: flex; flex-direction: column; justify-content: space-between;
  align-items: flex-end; font-size: .68rem; color: var(--faint);
  padding: 1px 0 3px; font-variant-numeric: tabular-nums; white-space: nowrap;
}
.pid-g-rad svg { width: 100%; display: block; }

/* Egenfrekvens-simulatoren gjenbruker `pid-*`-stillaset — glidere, linjer,
   grafer og aksetall er de samme tingene. Bare riggen og energisporet er
   nytt. */
.ef-modus { display: flex; gap: 6px; }

.ef-rigg { display: flex; gap: 22px; align-items: flex-start; flex-wrap: wrap; }
.ef-rigg > svg { flex: 0 0 auto; }
.ef-tall { flex: 1 1 260px; min-width: 0; display: grid; gap: 14px; align-content: center; }
.ef-tall > div { display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap; }
.ef-tall b {
  font-size: 1.3rem; font-weight: 700; font-variant-numeric: tabular-nums;
  letter-spacing: -.01em;
}
.ef-tall em { font-style: normal; font-size: .78rem; color: var(--muted); }

/* Ett spor med to andeler: fart til venstre, fjær til høyre. To separate
   stolper ville krevd at man sammenligner lengder; her er skillet ett sted
   å se, og summen er alltid hel. */
.ef-energi { align-items: center !important; }
.ef-e-spor {
  flex: 0 1 190px; min-width: 90px; height: 8px; border-radius: 4px;
  background: var(--accent-2); border: 1px solid var(--border); overflow: hidden;
}
.ef-e-spor > i { display: block; height: 100%; background: var(--accent); }
.ef-e-tekst { font-size: .74rem; color: var(--muted); flex: 0 1 auto; }

.ef-rpm-akse {
  display: flex; justify-content: space-between; font-size: .68rem;
  color: var(--faint); padding-left: 58px; margin-top: 2px;
}

/* Fluidisert sjikt. Gjenbruker `pid-*`-stillaset; det nye er beholderen,
   den log-skalerte vindusgrafen og tegnforklaringen under den. */
.fs-rigg { display: flex; gap: 24px; align-items: center; flex-wrap: wrap; }
.fs-rigg > svg { flex: 0 0 auto; }
.fs-tall { flex: 1 1 260px; min-width: 0; display: grid; gap: 13px; align-content: center; }
.fs-tall > div { display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap; }
.fs-tall b {
  font-size: 1.28rem; font-weight: 700; font-variant-numeric: tabular-nums;
  letter-spacing: -.01em;
}
.fs-tall em { font-style: normal; font-size: .78rem; color: var(--muted); }
.fs-regime { align-items: center !important; }
.fs-regime .muted { font-size: .8rem; flex: 1 1 180px; min-width: 0; }

.fs-vindu { margin-top: 4px; }
.fs-vindu > svg { width: 100%; display: block; }
/* Log-akse: merkene står der tallet faktisk er, ikke jevnt fordelt. */
.fs-vindu-akse {
  position: relative; height: 16px; font-size: .68rem; color: var(--faint);
  font-variant-numeric: tabular-nums;
}
.fs-vindu-akse > span { position: absolute; transform: translateX(-50%); }
.fs-tegnforklaring {
  display: flex; gap: 18px; flex-wrap: wrap; margin-top: 8px;
  font-size: .74rem; color: var(--muted);
}
/* Tegnforklaringen viser strekformen og ikke bare fargen, fordi de to
   kurvene ligger i den samme grafen og fargene står tett i flere temaer. */
.fs-tegnforklaring i {
  display: inline-block; width: 20px; height: 0; vertical-align: middle;
  margin-right: 6px;
}
.fs-tegnforklaring i.hel { border-top: 3px solid currentColor; }
.fs-tegnforklaring i.stiplet { border-top: 3px dashed currentColor; }

/* Pumpe og rørstrekk. De fem tallene man leser først står på én rad over
   grafene, ikke i sidespalten: driftspunkt, løftehøyde, effekt, Reynolds og
   NPSH-margin er svaret, og resten er utregningen bak det. */
.pu-topp { display: flex; flex-wrap: wrap; gap: 14px 32px; }
.pu-t { display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap; }
.pu-t b {
  font-size: 1.4rem; font-weight: 700; font-variant-numeric: tabular-nums;
  letter-spacing: -.01em;
}
.pu-t em { font-style: normal; font-size: .78rem; color: var(--muted); }
.pu-t .pid-t-etikett { flex: 1 0 100%; margin: 0 0 1px; }

.pid-glider { display: block; margin-bottom: 15px; }
.pid-g-topp {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 10px; margin-bottom: 5px;
}
.pid-g-topp b { font-variant-numeric: tabular-nums; font-size: .88rem; }

input[type=range] {
  -webkit-appearance: none; appearance: none; width: 100%; height: 22px;
  background: transparent; cursor: pointer; display: block;
}
input[type=range]::-webkit-slider-runnable-track {
  height: 5px; border-radius: 3px; background: var(--surface-inset);
  border: 1px solid var(--border);
}
input[type=range]::-moz-range-track {
  height: 5px; border-radius: 3px; background: var(--surface-inset);
  border: 1px solid var(--border);
}
input[type=range]::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none; width: 17px; height: 17px;
  border-radius: 50%; background: var(--accent); border: none;
  margin-top: -7px; box-shadow: var(--shadow);
}
input[type=range]::-moz-range-thumb {
  width: 17px; height: 17px; border-radius: 50%; background: var(--accent);
  border: none; box-shadow: var(--shadow);
}
input[type=range]:focus-visible::-webkit-slider-thumb {
  outline: 2px solid var(--accent); outline-offset: 2px;
}
input[type=range]:focus-visible::-moz-range-thumb {
  outline: 2px solid var(--accent); outline-offset: 2px;
}

.conn { padding: 16px 0; border-bottom: 1px solid var(--border); }
.conn:last-of-type { border-bottom: none; }
.conn-head { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.conn-head strong { font-size: .94rem; }

.logline {
  display: flex; gap: 12px; align-items: baseline;
  padding: 8px 0; border-bottom: 1px solid var(--border); font-size: .85rem;
}
.logline:last-child { border-bottom: none; }
.logline time { color: var(--faint); font-size: .76rem; white-space: nowrap; font-variant-numeric: tabular-nums; }
.logline .who { color: var(--muted); font-weight: 560; white-space: nowrap; }

.kv { display: grid; grid-template-columns: 168px 1fr; gap: 7px 14px; font-size: .86rem; }
.kv dt { color: var(--muted); }
/* `anywhere`, ikke `break-all`: en lang URL skal brekke midt i, men en
   vanlig setning skal fortsatt brekke mellom ord. */
.kv dd { overflow-wrap: anywhere; }

/* Commit-lista i oppdateringspanelet */
/* Stegene i en pågående oppdatering. Ett steg per linje, med sin egen
   status — en liste som fylles ut sier mer enn en knapp som snurrer. */
.fremdrift { display: flex; flex-direction: column; margin-top: 16px; }
.fremdrift .steg {
  display: flex; align-items: baseline; gap: 10px;
  padding: 7px 0; border-bottom: 1px solid var(--border);
  font-size: .85rem; color: var(--muted);
}
.fremdrift .steg:last-child { border-bottom: none; }
.fremdrift .steg .merke { flex: none; width: 15px; color: var(--muted); }
.fremdrift .steg.gjor { color: var(--text); }
.fremdrift .steg.gjor .merke { color: var(--accent); }
.fremdrift .steg.feil, .fremdrift .steg.feil .merke { color: var(--danger); }
.fremdrift .steg .detalj { font-size: .78rem; text-align: right; overflow-wrap: anywhere; }

.commits { display: flex; flex-direction: column; }
.commit {
  display: flex; align-items: baseline; gap: 12px;
  padding: 8px 0; border-bottom: 1px solid var(--border); font-size: .85rem;
}
.commit:last-child { border-bottom: none; }
.commit .sha {
  color: var(--accent); background: var(--accent-soft);
  padding: 1px 7px; border-radius: var(--r-sm); font-size: .78rem; flex: none;
}
.commit .faint { font-size: .77rem; white-space: nowrap; }

/* ============================ Modus ============================

   Kortene i modusvelgeren, i veiviserens modussteg og i invitasjonens
   velkomstprogram. Tre steder, ett utseende — de svarer på det samme
   spørsmålet, og tre ulike former for det ville sett ut som tre ulike valg.

   `auto-fit` og ikke tre faste kolonner: katalogen i app/moduser.py kan få
   en fjerde modus, og da skal rutenettet brekke selv i stedet for å presse
   fire kort inn på tre plasser. */
.modus-grid {
  display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
}
.modus-kort {
  display: flex; flex-direction: column; align-items: flex-start; gap: 4px;
  text-align: left; padding: 16px 15px 15px;
  border-radius: var(--r-md); border: 1.5px solid var(--border);
  background: transparent; color: var(--text);
  transition: border-color .15s, background .15s, transform .15s var(--ease);
}
.modus-kort:hover { border-color: var(--border-strong); transform: translateY(-1px); }
.modus-kort.on { border-color: var(--accent); background: var(--accent-soft); }
.modus-kort h3 { font-size: 1rem; font-weight: 650; }
.modus-kort p { color: var(--muted); font-size: .82rem; line-height: 1.45; }
.modus-kort .badge { margin-top: 6px; }
.modus-ico {
  width: 42px; height: 42px; border-radius: 12px; margin-bottom: 4px;
  display: grid; place-items: center;
  background: var(--surface-2); color: var(--muted);
  transition: background .15s, color .15s;
}
.modus-kort.on .modus-ico { background: var(--accent); color: var(--accent-contrast); }
/* Den lille varianten: i invitasjonens kortspalte og i inviter-vinduet er
   det ikke plass til det samme kortet i full størrelse. */
.modus-grid.liten { grid-template-columns: repeat(auto-fit, minmax(128px, 1fr)); gap: 8px; }
.modus-grid.liten .modus-kort { padding: 12px 12px 11px; }
.modus-grid.liten .modus-ico { width: 34px; height: 34px; border-radius: 10px; }
.modus-grid.liten .modus-kort h3 { font-size: .9rem; }
.modus-grid.liten .modus-kort p { font-size: .76rem; }

.modusvelger h1 { font-size: 1.4rem; }
.modusvelger .sub { color: var(--muted); font-size: .9rem; margin: 6px 0 20px; line-height: 1.5; }

/* ---- førstegangsintroen ----

   Samme kort som veiviseren, med ikonet til modusen øverst. Punktene er en
   liste og ikke et rutenett: de leses ovenfra og ned, én gang, og to
   kolonner ville laget en leserekkefølge ingen er enige om. */
.modusintro h1 { font-size: 1.4rem; margin-top: 14px; }
.modus-ico.stor { width: 56px; height: 56px; border-radius: 16px;
                  background: var(--accent-soft); color: var(--accent); }
.intro-punkter { display: flex; flex-direction: column; gap: 4px; margin-top: 4px; }
.intro-punkt { display: flex; gap: 12px; align-items: flex-start; padding: 10px 0; }
.intro-punkt + .intro-punkt { border-top: 1px solid var(--border); }
.ip-ico {
  width: 30px; height: 30px; border-radius: 9px; flex: none;
  display: grid; place-items: center;
  background: var(--surface-2); color: var(--muted);
}
.intro-punkt h4 { font-size: .92rem; font-weight: 640; }
.intro-punkt p { color: var(--muted); font-size: .85rem; line-height: 1.5; margin-top: 2px; }

/* ---- hilsenskortet: det første kortet i alle tre modusene ----

   To sider med hver sin jobb. Til venstre hvem du er og hvor du er — navnet
   med skolen, jobben eller husstanden som brikker under. Til høyre hva
   klokka er, med datoen under i mindre skrift.

   Klokka er det tyngste elementet på siden med vilje: det er tallet man
   sjekker uten å ha bestemt seg for å sjekke det. `num` gir den
   tabellsifrene som resten av tallene i portalen, så bredden ikke hopper når
   minuttet skifter fra 19 til 20 — uten det ville hele kortet sitret hvert
   tiende sekund. */
.dash .card.hilsen {
  display: flex; align-items: center; gap: 18px; justify-content: space-between;
  padding: 18px 22px; margin-bottom: 26px;
}
.hilsen-hvem { min-width: 0; }

/* Samme størrelse som hjemforsidens gamle `.greeting h1`. Kortet arvet en
   stund skoleforsidens mindre overskrift, og navnet ble da mindre enn det
   var før kortene ble slått sammen — hilsenen er det første man leser, og
   den skal ikke krympe fordi to sider ble til én. */
.card.hilsen h1 {
  font-size: clamp(1.6rem, 3.4vw, 2.2rem); font-weight: 680; letter-spacing: -.02em;
}

/* Brikkeraden holder plassen sin også når den er tom.

   Uten `min-height` ble kortet lavere for en konto uten husstand, skole
   eller jobb, og navnet flyttet seg opp — samme hilsen, to ulike steder,
   avhengig av noe som ikke har med hilsenen å gjøre. Nå står navnet på
   samme sted uansett, og kortet er like høyt i alle tre modusene. */
.hilsen-linje {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 7px; margin-top: 9px;
  /* Nøyaktig én brikkes høyde, regnet av `.hh-chip` sine egne tall:
     .85rem tekst på linjehøyde 1.5, pluss 8px padding og 1px kant oppe og
     nede. Et rundt tall her ville gjort kortet noen piksler lavere uten
     brikke enn med, og det er nettopp forskjellen denne regelen finnes for
     å fjerne. Endrer du brikka, endre denne. */
  min-height: calc(.85rem * 1.5 + 18px);
}

/* Brikka i hilsenskortet står uten pille. Navnet på skolen er en opplysning
   om deg, ikke en knapp blant flere, og en ramme rundt den konkurrerte med
   hilsenen rett over.

   Den beholder likevel sine 8 piksler over og under, og kanten står som
   `transparent` i stedet for å fjernes: høyden er nøyaktig det
   `min-height` over er regnet av, og tas polstringen bort blir kortet
   lavere uten brikke enn med — som er akkurat det den regelen finnes for å
   hindre. Bare det vannrette forsvinner, så teksten står på linje med
   hilsenen i stedet for å være rykket inn. */
.hilsen-linje { column-gap: 16px; }
.hilsen-linje .hh-chip {
  background: none; border-color: transparent; padding-left: 0; padding-right: 0;
}
.hilsen-linje a.hh-chip:hover, .hilsen-linje button.hh-chip:hover {
  border-color: transparent; color: var(--text);
}
/* Hjørnet øverst til høyre: små ikonknapper som hører til *stedet* kortet
   står på — globusen til arbeidsplassens nettside, tannhjulet til
   innstillingene hennes. Se `hilsenskort()` i app.js.

   `align-self: flex-start` er hele plasseringen: kortet er en flex-rad med
   loddrett sentrering, og uten den ville knappene stått midt på siden av
   klokka i stedet for i hjørnet. De tar ingen høyde fra kortet — 36 px mot
   kortets drøye åtti — så kortet er like høyt med og uten dem, som er
   nettopp det `min-height` på brikkelinja over finnes for å sikre. */
.hilsen-verktoy { display: flex; gap: 4px; flex: none; align-self: flex-start; }
.hilsen-naa { flex: none; text-align: right; line-height: 1.1; }
.hilsen-tid {
  display: block;
  font-size: clamp(2rem, 5.2vw, 2.9rem); font-weight: 700; letter-spacing: -.03em;
}
.hilsen-dato {
  display: block; margin-top: 4px;
  color: var(--muted); font-size: .8rem; white-space: nowrap;
}

/* ---- overskriftsrad med en knapp til høyre ----

   `.section-title` har linja som et `::after`, og et pseudoelement kommer
   etter alle virkelige barn — en knapp inni ville derfor havnet foran linja
   og altså midt i raden. Den står i stedet ved siden av, i en rad som eier
   marginen. */
.section-rad { display: flex; align-items: center; gap: 12px; margin: 30px 0 12px; }
.section-rad .section-title { margin: 0; flex: 1; min-width: 0; }

.plussknapp {
  flex: none; display: grid; place-items: center;
  width: 32px; height: 32px; border-radius: var(--r-pill);
  background: var(--surface); border: 1px solid var(--border); color: var(--muted);
  cursor: pointer; transition: border-color .15s, color .15s, transform .15s var(--ease);
}
.plussknapp:hover {
  border-color: var(--border-strong); color: var(--text); transform: translateY(-1px);
}

/* ---- et tilbud som venter ----

   Formen er skolekortets, så de to leses som det samme slaget ting. Den
   stiplede kanten er forskjellen som ikke er en farge: et tilbud er ikke din
   skolegang ennå, og i et lyst tema der `--accent` og kantfargen ligger tett,
   er en strek man kan *se formen på* det som skiller dem. */
.module-card.invitert {
  border-style: dashed; cursor: default;
  padding-bottom: 14px;
}
.module-card.invitert:hover { transform: none; border-color: var(--border); }
.m-flag.invitert { background: var(--accent-soft); color: var(--accent); }
.m-foot.invitert-knapper {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; flex-wrap: wrap;
}

/* ---- fagene i full sidebredde ----

   Et fag er en tekst man skal lese seg gjennom, ikke en flis man finner
   igjen på farge og ikon, og lista er studieplanens rekkefølge — en
   progresjon leses nedover. Derfor kort i full bredde og ikke rutenettet
   modulene bruker. */
.fagliste { display: flex; flex-direction: column; gap: 8px; }
.fag-bolk {
  font-size: .82rem; font-weight: 640; color: var(--muted);
  margin: 18px 0 8px;
}
.fagliste .fag-bolk:first-child { margin-top: 0; }

.fagkort {
  display: flex; align-items: center; gap: 14px; width: 100%;
  padding: 15px 18px; border-radius: var(--r-md);
  background: var(--surface); border: 1px solid var(--border); color: var(--text);
  transition: border-color .15s, transform .15s var(--ease);
}
.fagkort:hover { border-color: var(--border-strong); transform: translateY(-1px); }
.fag-ico {
  flex: none; display: grid; place-items: center;
  width: 40px; height: 40px; border-radius: var(--r-md);
  background: var(--accent-soft); color: var(--accent);
}
.fagkort .grow { min-width: 0; }
.fagkort b { display: block; font-size: .97rem; font-weight: 640; }
.fag-merke {
  display: block; font-size: .72rem; font-weight: 640; letter-spacing: .04em;
  text-transform: uppercase; color: var(--faint); margin-bottom: 2px;
}
.fag-sub {
  display: block; color: var(--muted); font-size: .86rem;
  line-height: 1.45; margin-top: 3px;
}
.fag-merker {
  flex: none; display: flex; align-items: center; gap: 8px; color: var(--faint);
}

/* På en telefon har ikke merkene plass ved siden av en emnetittel. Presset
   man dem inn der, ble «Kjelanlegg, kjelkonstruksjoner og komponenter» tre
   linjer i en spalte på to tredjedels bredde. De legger seg derfor på sin
   egen rad under teksten, høyrestilt — `flex-basis: 100%` er det som bryter
   raden, og ikonet og teksten beholder sin. */
@media (max-width: 560px) {
  .fagkort {
    flex-wrap: wrap; align-items: flex-start; gap: 6px 11px; padding: 13px 14px;
  }
  .fagkort .grow { flex: 1 1 0; }
  .fag-merker { flex: 1 0 100%; justify-content: flex-end; }
}

/* Kortet som viser skolen på innløsningssiden for en invitasjon. Den siden
   står utenfor skallet, så kortet får ingen av `.dash`-reglene. */
.skoleinv-kort {
  display: flex; align-items: center; gap: 14px; text-align: left;
  margin: 4px 0 14px; padding: 14px 16px;
}
.skoleinv-kort h3 { font-size: .98rem; font-weight: 640; }
.skoleinv-kort p { color: var(--muted); font-size: .86rem; margin-top: 3px; }

/* Inngangen til en flate som ligger utenfor lista over den: læringsportalen
   fra skoleforsiden, hovedprosjektet fra kurssiden. Samme form begge steder
   fordi det er den samme bevegelsen — ut av det du ser på, inn i noe
   større. */
.lp-inngang { display: flex; align-items: center; gap: 16px; margin-top: 26px; }
.lp-inngang h2 { font-size: .97rem; }
.lp-inngang p { color: var(--muted); font-size: .86rem; margin-top: 3px; line-height: 1.5; }
.lp-inngang .btn { flex: none; }

/* På en telefon får datoen ikke plass ved siden av et navn og en brikke uten
   at noe av det brytes midt i. Kortet legges derfor om til to linjer: klokka
   og datoen øverst på sin egen rad, navnet under. Rekkefølgen snus med
   `order` og ikke i markup, så det er fortsatt ett kort i dokumentet. */
@media (max-width: 620px) {
  .dash .card.hilsen {
    flex-direction: column; align-items: flex-start; gap: 10px; padding: 16px 17px;
  }
  .hilsen-hvem, .hilsen-naa { width: 100%; }
  .hilsen-linje { min-height: 0; }
  .hilsen-linje:empty { display: none; }
  .hilsen-naa {
    order: -1; text-align: left;
    display: flex; align-items: baseline; gap: 10px;
  }
  .hilsen-tid { font-size: 2.1rem; }
  .hilsen-dato { margin-top: 0; white-space: normal; }
  /* I én spalte er det klokkeraden som ligger øverst (`order: -1`), så
     hjørnet tas ut av flyten for å bli i hjørnet. Polstringen til høyre er
     de to knappenes bredde: uten den legger datoen seg under dem, og
     «Søndag 27. september 2026» brytes midt i et ord som ingenting. */
  .card.hilsen.har-verktoy { position: relative; }
  .har-verktoy .hilsen-verktoy { position: absolute; top: 9px; right: 9px; }
  .har-verktoy .hilsen-naa { padding-right: 82px; }
  .lp-inngang { flex-direction: column; align-items: stretch; }
  .lp-inngang .btn { justify-content: center; }
}

@media (max-width: 620px) {
  .kv { grid-template-columns: 1fr; gap: 2px; }
  .kv dt { margin-top: 8px; font-size: .78rem; }
  .commit { flex-wrap: wrap; gap: 6px 10px; }
  .commit .grow { flex-basis: 100%; white-space: normal; }
}

/* ============================ Nettbrett ============================ */

/* Et nettbrett i stående modus (en iPad 12,9" er 1024 px bred) er bredere
   enn en telefon, så hele toppnavigasjonen vises — men sammen med
   varselmerkene, nett/lokalt-bryteren og brukermenyen blir summen bredere
   enn skjermen, og bryteren ble kuttet i høyrekanten. Samme grep som lenger
   ned på telefon: teksten som gjentar det ikonet allerede sier ryker først.
   Merkene beholder ikon og tall (og tittelattributtet, så de forklarer seg
   ved trykk-og-hold); navigasjonslenkene beholder teksten sin og mister
   ikonet i stedet — det er teksten toppmenyen er til for. Målt med alt på
   en gang (driftsvarsel, oppdatering, nett/lokalt) går toppmenyen fra
   ~1330 px til under 961 px med dette. Under 960 tar bunnmenyen over, se
   neste bolk. */

/* Merketeksten først: den sier det ikonet, tallet og tittelattributtet
   allerede sier, og med begge merkene framme er det den som dytter
   nett/lokalt-bryteren ut av skjermen. Gjelder også telefon — der er det
   merkene som gjør toppen trang når de først dukker opp. */
@media (max-width: 1340px) {
  .update-chip .lbl-txt { display: none; }
}

@media (min-width: 961px) and (max-width: 1200px) {
  .topbar { gap: 10px; }
  .topnav a { padding: 7px 9px; }
  .topnav a .ico { display: none; }
  .segmented button span.lbl-txt { display: none; }
  .usermenu .who { display: none; }
}

/* ============================ Mobil ============================ */

/* Bunnmeny på telefon — tommelen når ikke toppen av skjermen. Grensa er
   960 og ikke 840: smale nettbrett i stående modus (en Surface er 912 px)
   har ikke plass til toppnavigasjonen selv uten tekstetikettene rundt, og
   en bunnmeny er innen tommelens rekkevidde der også. */
.tabbar { display: none; }

@media (max-width: 960px) {
  .topnav { display: none; }
  .usermenu .who { display: none; }

  .tabbar {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 35;
    display: flex; justify-content: space-around; align-items: stretch;
    padding: 6px 4px calc(6px + env(safe-area-inset-bottom));
    background: color-mix(in srgb, var(--bg) 88%, transparent);
    backdrop-filter: saturate(180%) blur(14px);
    -webkit-backdrop-filter: saturate(180%) blur(14px);
    border-top: 1px solid var(--border);
  }
  .tabbar a {
    flex: 1; display: flex; flex-direction: column; align-items: center; gap: 3px;
    padding: 6px 2px; border-radius: var(--r-sm);
    font-size: .67rem; font-weight: 560; color: var(--muted);
  }
  .tabbar a.on { color: var(--accent); }

  .page, .dash { padding-bottom: calc(96px + env(safe-area-inset-bottom)); }
  .aria-fab { bottom: calc(78px + env(safe-area-inset-bottom)); right: 16px; width: 48px; height: 48px; }
  .aria-panel { left: 12px; right: 12px; width: auto; bottom: calc(136px + env(safe-area-inset-bottom)); height: min(480px, calc(100vh - 240px)); }
}

@media (max-width: 640px) {
  .module-grid { grid-template-columns: 1fr 1fr; gap: 10px; }
  .module-card { padding: 14px; min-height: 132px; }
  .module-card .m-ico { width: 34px; height: 34px; }
  .module-card h3 { font-size: .91rem; margin-top: 11px; }
  .module-card p { font-size: .75rem; }
  .module-card .m-arrow { display: none; }
  .pick-grid { grid-template-columns: 1fr; }
  .theme-slide { flex: 0 0 88%; }
  .kpi-strip { grid-template-columns: 1fr 1fr; }
  /* På en telefon får navnet og fire nivåknapper ikke plass på samme linje.
     Navnet, kvitteringen og tannhjulet blir stående øverst; velgeren legger
     seg under og fyller bredden, så knappene er store nok til en tommel.
     `order` på velgeren alene holder — resten står i den rekkefølgen de er
     skrevet, og et `order` på kvitteringen ville sendt den forbi tannhjulet. */
  .modul-rad { flex-wrap: wrap; gap: 8px 10px; padding: 11px 0; }
  .modul-rad .nivaa-velger { order: 5; flex: 1 0 100%; }
  .modul-rad .nivaa-velger button {
    flex: 1; text-align: center; white-space: nowrap; padding: 8px 6px;
  }
  .tannhjul-plass { display: none; }
  .modul-adresse { flex-wrap: wrap; }
  .modul-adresse .btn { width: 100%; }
  .day-row { flex-direction: column; gap: 7px; }
  .day-name { width: auto; flex-direction: row; gap: 8px; align-items: baseline; }
  .additem { flex-wrap: wrap; }
  .additem input { min-width: 0; }
  .modal { max-height: 92vh; }
  .tbl-wrap { margin: 0 -16px; padding: 0 16px; }
}

@media (max-width: 430px) {
  /* Bryteren beholder ikonene; teksten «Nett»/«Lokalt» er det første som
     ryker når toppmenyen blir trang. */
  .segmented button span.lbl-txt { display: none; }
}

@media (max-width: 340px) {
  .brand span.wordmark { display: none; }
}

/* ── Felles innlogging (Admin → Felles innlogging) ──────────────────────
   Små byggeklosser som bare brukes av den siden. De ligger her og ikke i
   en egen fil av samme grunn som resten av Bifrost er som det er: én
   stilfil, ingen byggesteg, ingenting som må kompileres før noe kan fikses. */

.checkrow {
  display: flex; align-items: flex-start; gap: 9px;
  margin: 0 0 8px; cursor: pointer; line-height: 1.45;
}
.checkrow input { margin-top: 4px; flex: none; }
.checkrow span { color: var(--text); }
.checkrow em { color: var(--muted); font-style: normal; font-weight: 600; }

.rw-list { margin: 4px 0 2px; }

.dim { color: var(--muted); font-weight: 400; }

/* Hemmeligheten vises én eneste gang. Den skal være lett å merke og
   kopiere, og den skal ikke brekke layouten om den er lang. */
.kode {
  margin: 10px 0 0; padding: 12px 14px;
  background: var(--surface-inset); border: 1px solid var(--border);
  border-radius: 10px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .88rem; overflow-wrap: anywhere; white-space: pre-wrap;
}

/* ---- forslagstavla ---- */
/* Et kort som er en <details>: sammenslått rad øverst, innhold under.
   Het `.forslag-sak` da Innmeldinger var eneste bruker; personvern-
   henvendelsene har samme form og samme behov, og to navn for samme ting er
   ett navn for mye. */
.sak-kort > summary { list-style: none; cursor: pointer; }
.sak-kort > summary::-webkit-details-marker { display: none; }
.sak-kort > summary .rw { padding: 12px 16px; }
.sak-kort[open] > summary .rw { border-bottom: 1px solid var(--border); margin-bottom: 12px; }
.sak-kort { padding: 0; }

/* Transkriber */

/* Hele opptaksraden er en knapp — da virker Enter og fokusring gratis.
   Tilbakestillingen under er det som skal til for at en <button> ser ut
   som de andre .rw-radene. */
button.rw-klikk {
  width: 100%; text-align: left; background: none; border: 0;
  border-bottom: 1px solid var(--border);
  font: inherit; color: inherit; cursor: pointer;
}
button.rw-klikk:hover .name { color: var(--accent); }

/* Ingen egen rullerute. Teksten sto en gang i en boks på 60vh med sin egen
   rullefelt, fordi tre kort under hverandre ellers ble en side uten ende —
   og da rullet man et transkript inni en side som også rullet, uten å vite
   hvilken av de to musehjulet traff. På ett opptak er de tre nå faner, så
   flaten står alene og sidens egen rulling holder. */
.opptak-tekst {
  white-space: pre-wrap; overflow-wrap: break-word;
  font-size: .92rem; line-height: 1.65;
}

.opptak-nedlast {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin-top: 12px;
}
.opptak-nedlast .grow { flex: 1; }

.opptak-faner { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 10px; }

/* Språkvelgeren på nedlastingslinja — uten etikett og uten å ta hele bredden. */
.field.kompakt { margin: 0; width: auto; }
.field.kompakt .lbl { display: none; }
.field.kompakt select {
  width: auto; min-width: 120px;
  padding: 6px 28px 6px 10px; font-size: .84rem;
}

.opplast-bar {
  height: 6px; border-radius: 3px; background: var(--accent-soft);
  overflow: hidden; margin-top: 10px; display: none;
}
.opplast-bar > div {
  height: 100%; width: 0; background: var(--accent); transition: width .2s;
}

/* ------------------------------------------------------------- lagring
   Diskene på serveren, som søyler.

   Søyla er delt i to fylte deler og ikke én. «Brukt» sier hvor full disken
   er, men det den som drifter faktisk lurer på er om det er *portalens*
   filer som spiser plassen eller alt det andre på maskinen. Med én farge må
   du regne den forskjellen i hodet; med to ser du den. */
.disk-liste {
  display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fit, minmax(272px, 1fr));
}
.disk {
  background: var(--surface-inset); border: 1px solid var(--border);
  border-radius: var(--r-md); padding: 14px 15px 13px;
}
.disk-topp { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.disk-topp h3 { font-size: .95rem; font-weight: 650; margin: 0; }
.disk-topp > svg { color: var(--muted); flex: none; }
.disk-topp .sti { font-size: .76rem; color: var(--faint); }

.disk-bar {
  height: 10px; border-radius: var(--r-pill); overflow: hidden;
  background: var(--surface-2); display: flex; margin: 11px 0 10px;
}
.disk-bar i { display: block; height: 100%; transition: width .3s var(--ease); }
.disk-bar i.portal { background: var(--accent); }
.disk-bar i.annet { background: var(--border-strong); }
/* Nesten full disk er en driftsbeskjed, ikke en detalj — da bytter «alt
   annet» til varselfargen i stedet for å være en nøytral grå strek. */
.disk.trang .disk-bar i.annet { background: var(--warn); }

.disk-tall { font-size: .82rem; color: var(--muted); margin-bottom: 9px; }
.disk-tall b { color: var(--text); font-weight: 640; font-variant-numeric: tabular-nums; }
.disk.trang .disk-tall b.pst { color: var(--warn); }

.disk-legende { display: flex; flex-wrap: wrap; gap: 3px 14px; font-size: .78rem; color: var(--muted); }
.disk-legende .prikk::before {
  content: ''; display: inline-block; width: 8px; height: 8px;
  border-radius: 2px; margin-right: 6px; background: currentColor;
  vertical-align: baseline;
}
.disk-legende .prikk.portal::before { background: var(--accent); }
.disk-legende .prikk.annet::before { background: var(--border-strong); }
.disk.trang .disk-legende .prikk.annet::before { background: var(--warn); }
.disk-roller { margin-top: 10px; display: flex; flex-wrap: wrap; gap: 6px; }
.disk-rolle {
  font-size: .76rem; color: var(--muted); background: var(--surface-2);
  border-radius: var(--r-pill); padding: 3px 10px;
}
.disk-rolle b { color: var(--text); font-weight: 620; font-variant-numeric: tabular-nums; }
.disk-knapp { margin-top: 12px; }

/* ---- filblaeren ----
   En liste, ikke et tre: en mappe om gangen med en brødsmulesti over. Et tre
   som kan foldes ut i alle retninger ville sett ut som noe du kan flytte på,
   og det er nettopp det du ikke kan her. */
.filbla-sti {
  display: flex; flex-wrap: wrap; align-items: center; gap: 2px;
  font-size: .82rem; margin-bottom: 10px;
}
.filbla-sti button {
  background: none; border: 0; padding: 3px 6px; border-radius: var(--r-sm);
  color: var(--accent); cursor: pointer; font: inherit;
}
.filbla-sti button:hover { background: var(--accent-soft); }
.filbla-sti button:last-child { color: var(--text); cursor: default; }
.filbla-sti button:last-child:hover { background: none; }
.filbla-sti .skille { color: var(--faint); }

.filbla-liste { border: 1px solid var(--border); border-radius: var(--r-md); overflow: hidden; }
.filrad {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 9px 12px; font: inherit; color: var(--text); text-align: left;
  background: none; border: 0; border-top: 1px solid var(--border);
}
.filbla-liste > :first-child { border-top: 0; }
button.filrad { cursor: pointer; }
button.filrad:hover, button.filrad:focus-visible { background: var(--surface-2); }
.filrad svg { color: var(--faint); flex: none; }
button.filrad svg { color: var(--accent); }
.filrad .navn { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: .88rem; }
.filrad .meta { font-size: .78rem; color: var(--faint); font-variant-numeric: tabular-nums; flex: none; }

/* Et bilde i en dokumentliste vises som seg selv. Et generisk fil-ikon sier
   ingenting om bildet fra sommerfesten — da må du laste det ned for å se
   hva det er, og det er én omvei for hver fil. */
.dok-bilde {
  width: 32px; height: 32px; flex: none; display: block; overflow: hidden;
  border-radius: var(--r-sm); background: var(--surface-2);
  border: 1px solid var(--border);
}
.dok-bilde img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ------------------------------------------- forslag fra sammendraget
   Tittel, dato og notat som språkmodellen foreslo. Avkryssinger og ikke en
   automatisk utfylling: modellen leser et maskinlaget transkript, og det du
   selv skrev er som regel riktigere enn det den gjettet. Derfor står den
   gamle verdien under den nye — du skal se hva du bytter bort, ikke bare
   hva du får. */
.forslag-kort { border-color: var(--accent-soft); }
.forslag-kort h2 svg { vertical-align: -3px; color: var(--accent); }

.forslag-rad {
  display: flex; align-items: flex-start; gap: 11px;
  padding: 10px 2px; cursor: pointer;
}
.forslag-rad + .forslag-rad { border-top: 1px solid var(--border); }
.forslag-rad input { position: absolute; opacity: 0; width: 0; height: 0; }
.forslag-rad .track {
  width: 19px; height: 19px; flex: none; margin-top: 2px;
  border-radius: 6px; background: var(--surface-inset);
  border: 1px solid var(--border-strong); position: relative;
  transition: background .15s var(--ease), border-color .15s;
}
.forslag-rad .track::after {
  content: ""; position: absolute; inset: 0;
  background: var(--accent-contrast); opacity: 0;
  transition: opacity .15s;
  /* Haken tegnes som en maske, så den arver fargen og ikke trenger et ikon
     i markup — rada er en <label>, og et <svg> inni den ville vært et
     klikkmål til uten grunn. */
  clip-path: polygon(19% 50%, 8% 61%, 40% 88%, 92% 28%, 81% 19%, 39% 68%);
}
.forslag-rad input:checked + .track { background: var(--accent); border-color: var(--accent); }
.forslag-rad input:checked + .track::after { opacity: 1; }
.forslag-rad input:focus-visible + .track { box-shadow: 0 0 0 3px var(--accent-soft); }

.forslag-rad .lbl {
  display: block; font-size: .72rem; letter-spacing: .05em;
  text-transform: uppercase; color: var(--faint); margin-bottom: 1px;
}
.forslag-rad .ny { display: block; font-size: .9rem; line-height: 1.5; }
.forslag-rad .naa {
  display: block; font-size: .78rem; color: var(--faint); margin-top: 3px;
}

/* --------------------------------------------- flere filer om gangen
   Lista over det du har valgt, med tilstand per fil. Én rad som blir grønn
   mens de andre står i kø sier mer enn én framdriftssøyle for alt: velger
   du sju møteopptak, er spørsmålet «hvor langt er den kommet, og hvilken
   av dem er det som feilet». */
.opplast-liste:not(:empty) {
  border: 1px solid var(--border); border-radius: var(--r-md);
  margin: -4px 0 14px; overflow: hidden;
}
.opplast-rad {
  display: flex; align-items: center; gap: 9px; padding: 8px 11px;
  font-size: .86rem;
}
.opplast-rad + .opplast-rad { border-top: 1px solid var(--border); }
.opplast-rad svg { color: var(--faint); flex: none; }
.opplast-rad .navn {
  flex: 1; min-width: 0; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap;
}
.opplast-rad .meta { color: var(--faint); font-size: .78rem; flex: none; }

.opplast-rad.gjor { background: var(--accent-soft); }
.opplast-rad.gjor svg { color: var(--accent); }
.opplast-rad.ok svg { color: var(--ok); }
.opplast-rad.ok .navn { color: var(--muted); }
.opplast-rad.bad { background: var(--danger-soft); }
/* «Disse kommer ikke gjennom» står mellom fillista og neste felt, og trenger
   luft under seg — uten den klistrer den seg inntil etiketten «Språk i
   opptaket» og leses som en del av den. */
#opForStore { margin-bottom: 14px; line-height: 1.5; }
.opplast-rad.bad svg { color: var(--danger); }

/* Døra til den lokale adressen, i opplastingsvinduet. Står nederst og ikke
   øverst med vilje: den er en snarvei for den som drifter maskinen, ikke
   noe den som bare skal laste opp en fil trenger å ta stilling til. */
.lokal-vei {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-top: 14px; padding: 11px 13px;
  background: var(--surface-inset); border: 1px solid var(--border);
  border-radius: var(--r-md);
  font-size: .82rem; color: var(--muted); line-height: 1.5;
}
.lokal-vei svg { color: var(--accent); flex: none; }
.lokal-vei .grow { min-width: 190px; }

/* ---- transkribererens to valg, og datoforslagene ---- */
.trValg {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  margin-bottom: 14px; padding: 13px 16px;
}
.trValg .field { margin: 0; }

/* Datoene vi fant, som noe å trykke på. De *settes* ikke av seg selv, og
   derfor ser de ut som valg og ikke som verdier. */
.dato-forslag { display: flex; flex-wrap: wrap; gap: 7px; margin: -4px 0 14px; }
.dato-forslag .chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 11px; border-radius: var(--r-pill); cursor: pointer;
  background: var(--surface-inset); border: 1px solid var(--border);
  color: var(--text); font: inherit; font-size: .82rem;
}
.dato-forslag .chip:hover { border-color: var(--accent); }
.dato-forslag .chip span { color: var(--faint); font-size: .76rem; }
.dato-forslag .chip.fjern { color: var(--muted); }
.dato-forslag .chip.fjern:hover { border-color: var(--danger); color: var(--danger); }

/* Sammendraget er formatert, ikke rå tekst — da må `pre-wrap` bort. Med den
   på fikk hvert <li> med seg linjeskiftene rundt seg som luft, og lista falt
   fra hverandre. */
.opptak-tekst.formatert { white-space: normal; }
.opptak-tekst.formatert h4 {
  font-size: .88rem; font-weight: 680; margin: 16px 0 6px; color: var(--text);
}
.opptak-tekst.formatert h4:first-child { margin-top: 0; }
.opptak-tekst.formatert p { margin: 0 0 10px; }
.opptak-tekst.formatert ul,
.opptak-tekst.formatert ol { margin: 0 0 12px; padding-left: 22px; }
.opptak-tekst.formatert li { margin-bottom: 5px; }
.opptak-tekst.formatert li::marker { color: var(--faint); }
.opptak-tekst.formatert strong { font-weight: 660; color: var(--text); }
.opptak-tekst.formatert > :last-child { margin-bottom: 0; }

/* Framdriften i fila som males nå. Tynn og under teksten, ikke ved siden av:
   den er en tilstand som endrer seg, ikke en opplysning om opptaket. */
.fremdrift { display: flex; align-items: center; gap: 8px; margin-top: 6px; }
.fremdrift-bar {
  flex: 1; height: 4px; border-radius: 2px; overflow: hidden;
  background: var(--surface-2); max-width: 220px;
}
.fremdrift-bar i {
  display: block; height: 100%; background: var(--accent);
  transition: width .4s var(--ease);
}
.fremdrift span { font-size: .74rem; color: var(--muted); font-variant-numeric: tabular-nums; }
.tabs .badge.liten { margin-left: 2px; }

/* ==================== vilkår, personvern og samtykke ====================
   Alt her bruker temavariablene og ingen faste farger, av samme grunn som
   resten: en juridisk tekst skal være like lesbar i et lyst tema som i et
   mørkt, og det er de lyse som avslører kontrastfeil. */

/* Avkrysning med en forklaring under. Hele raden er klikkbar — en
   avkrysningsboks på 13 px er ikke et treffområde på en telefon. */
.avkryss {
  display: flex; align-items: flex-start; gap: 11px;
  padding: 11px 13px;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface-inset);
  cursor: pointer;
  transition: border-color .15s ease;
}
.avkryss:hover { border-color: var(--border-strong); }
.avkryss:focus-within { border-color: var(--accent); }
.avkryss input[type=checkbox] {
  width: 17px; height: 17px; margin-top: 1px;
  flex: none; accent-color: var(--accent); cursor: pointer;
}
.avkryss > span { display: block; font-size: .87rem; line-height: 1.5; }
.avkryss strong { display: block; font-weight: 600; }
.avkryss .hint { display: block; margin-top: 3px; }
.avkryss.valgfri { margin-top: 10px; }

.samtykke-liste { display: flex; flex-direction: column; gap: 9px; }

/* Raden *er* kortet, og «Les» ligger inne i det. Lå knappen utenfor, ble de
   påkrevde radene smalere enn den valgfrie under, og tre bokser som nesten
   flukter leses som en feil. */
.samtykke-rad {
  display: flex; align-items: center; gap: 11px;
  padding: 11px 13px;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface-inset);
}
.samtykke-rad > .avkryss {
  flex: 1; min-width: 0;
  border: 0; background: none; padding: 0;
}
.samtykke-rad > span:first-child { flex: 1; min-width: 0; font-size: .87rem; line-height: 1.5; }
.samtykke-rad > span:first-child strong { display: block; font-weight: 600; }
.samtykke-rad .btn, .samtykke-rad > a { flex: none; }

/* Godkjenningsskjermen er bredere enn innloggingen: to dokumenter med
   forklaring under får ikke plass på 360 px uten å bli en tekstvegg. */
.samtykke-kort { max-width: 520px; text-align: left; }
.samtykke-kort h1, .samtykke-kort .sub, .samtykke-kort .auth-logo { text-align: center; }
.samtykke-kort .sub { margin-bottom: 18px; }

/* Lenkene under innloggingskortet. Små med vilje — de skal være der for den
   som leter, ikke konkurrere med «Logg inn». */
.auth-juss {
  margin-top: 16px; text-align: center;
  font-size: .8rem; color: var(--faint);
}
.auth-juss a { color: var(--muted); text-decoration: none; }
.auth-juss a:hover { color: var(--text); text-decoration: underline; }
.auth-juss span { margin: 0 7px; }

/* Selve dokumentteksten. Smalere linjelengde enn resten av portalen: en
   personvernerklæring leses i sammenheng, og 90 tegn per linje leses ikke.

   **Én spalte, og bare figurer og tabeller slipper ut av den.** Bredden lå
   før som `max-width: 68ch` på hvert element for seg, og det ga fire ulike
   bredder i samme dokument: avsnittet fikk 68ch, lista 68ch minus
   punktinnrykket, sitatet 68ch minus kanten, og overskrifter, tabeller og
   figurer hele kortet. `box-sizing: border-box` spiste innrykket fra
   bredden, så to elementer med samme `max-width` ble ulikt brede. Ingen av
   forskjellene var ment; de leses som at noe er i stykker.

   Nå er målet ett sted (`--maal`), og rutenettet gir hvert barn samme
   spalte. Figurer og tabeller står i `full` fordi bredden er innholdet
   deres — en skisse med tjue etiketter og en tabell med åtte kolonner blir
   ulesbare i en lesespalte — men de starter på samme venstrekant som
   teksten, så sida har én loddrett linje og ikke to.

   `--marg` er brønnen til venstre for teksten. Punktmerker og sitatkanten
   henger der, slik at *teksten* står på samme kant enten den er et avsnitt,
   et punkt eller et sitat. `min(100%, …)` er der fordi en fast spalte
   bredere enn skjermen ikke krymper av seg selv: uten den rant fagstoffet
   ut av mobilskjermen. */
.juss-tekst {
  font-size: .9rem; line-height: 1.62; color: var(--text);
  --maal: 78ch;
  --marg: 20px;
  display: grid;
  grid-template-columns:
    [full-start tekst-start] min(100%, var(--maal)) [tekst-end] 1fr [full-end];
}
.juss-tekst > * { grid-column: tekst; min-width: 0; padding-left: var(--marg); }
.juss-tekst > figure, .juss-tekst > .tabell-rull { grid-column: full; }
.juss-tekst > *:first-child { margin-top: 0; }
/* Overskriftsstigen. Den lå på 1.15 / 1 / .92rem mot en brødtekst på .9 —
   fire trinn innenfor et halvt punkt, som i praksis er ett trinn: et kapittel
   og et underkapittel så like ut, og et fagstoff på seks tusen ord uten
   synlig inndeling er en vegg. Permen selv skiller dem tydelig, og det er
   den som er fasiten her.

   Kapittelet får en hårstrek over seg i tillegg til størrelsen, og streken
   går i full bredde og ikke bare over lesespalta: den deler emnet, ikke
   avsnittet, og en strek som stopper midt på sida deler ingenting. Første
   barn får den ikke — en strek rett under kortkanten er en dobbel kant. */
.juss-tekst h1 { font-size: 1.5rem; font-weight: 700; margin: 30px 0 12px;
                 letter-spacing: -.01em; }
.juss-tekst h2 {
  grid-column: full;
  font-size: 1.25rem; font-weight: 700; letter-spacing: -.01em;
  margin: 34px 0 12px; padding-top: 16px;
  border-top: 1px solid var(--border);
}
.juss-tekst > h2:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
.juss-tekst h3 { font-size: 1.02rem; font-weight: 650; margin: 26px 0 8px; }
.juss-tekst p { margin: 0 0 12px; color: var(--muted); }
.juss-tekst strong { color: var(--text); font-weight: 600; }
.juss-tekst em { color: var(--text); font-style: italic; }
.juss-tekst ul { margin: 0 0 13px; color: var(--muted); }
.juss-tekst li { margin-bottom: 5px; }
.juss-tekst code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .85em; padding: 1px 5px;
  background: var(--surface-inset); border-radius: 5px; color: var(--text);
}
.juss-tekst a { color: var(--accent); }

/* Skisser og diagrammer fra kursmateriellet. Bildene er avfotograferte
   sider — lyse ark med tynne streker — så de får en egen hvit bunn og en
   ramme i stedet for å flyte rett på temaets bakgrunn. Uten bunnen ble en
   strektegning på et mørkt tema stående som en lysende flekk med
   halvgjennomsiktige kanter.

   Bredere enn lesespalta, se rutenettet over: en skisse med tjue etiketter
   er ulesbar på en lesespaltes bredde, og en figur er det ene stedet i et
   fagstoff der bredde faktisk er innholdet. */
.juss-tekst figure { margin: 0 0 18px; }
.juss-tekst figure a { display: block; }
.juss-tekst figure img {
  display: block; width: 100%; height: auto;
  background: #fff; border: 1px solid var(--border); border-radius: 8px;
  cursor: zoom-in;
}
.juss-tekst figure a:hover img { border-color: var(--accent); }
.juss-tekst figcaption {
  margin-top: 7px; font-size: .82rem; line-height: 1.45;
  color: var(--muted);
}

/* Sitert forskrifts- og veiledningstekst i fagstoffet.

   **Permen setter den ordrette lovteksten i blå kursiv på en lys blå
   flate**, og det er ikke pynt: det er skillet mellom hva forskriften sier
   og hva kursholderen mener den betyr. Her var sitatet bare en tynn kant, og
   en kant er lett å lese forbi — særlig i et emne der annenhver setning
   allerede er uthevet. Nå er det en flate, som i permen.

   Fargen er `--accent` og ikke en fast blå. Permen har én farge å velge i;
   portalen har sju temaer som skifter både bakgrunn og aksent, og en
   hardkodet blå ville vært riktig i ett av dem. `color-mix` mot bakgrunnen
   holder flaten lys nok til at teksten står, i både lyse og mørke temaer.

   Kursiv er utelatt med vilje. Permen har korte utdrag; her står det
   paragrafer på to hundre ord, og to hundre ord kursiv leses dårligere enn
   de samme ordene rett opp og ned. Flaten og kanten sier det samme kursiven
   skulle si. */
.juss-tekst blockquote {
  margin: 0 0 10px;
  padding: 12px var(--marg) 12px calc(var(--marg) - 3px);
  border-left: 3px solid var(--accent);
  border-radius: 0 8px 8px 0;
  background: color-mix(in srgb, var(--accent) 9%, transparent);
  color: var(--text);
}
/* Flere ledd av samme paragraf er flere sitatblokker etter hverandre.
   De skal lese som én flate med luft mellom leddene, ikke som fire
   løsrevne sitater — derfor tettere avstand mellom to naboer. */
.juss-tekst blockquote + blockquote { margin-top: -4px; }
.juss-tekst blockquote:last-child { margin-bottom: 14px; }

/* Tabellen med lagringstider. Egen rulling, så en lang rad ikke gjør hele
   siden bredere enn skjermen — samme regel som ellers i portalen. */
.tabell-rull { overflow-x: auto; margin: 0 0 16px; }
.tabell-rull table { border-collapse: collapse; width: 100%; min-width: 320px; }
.tabell-rull th, .tabell-rull td {
  text-align: left; padding: 8px 12px 8px 0;
  border-bottom: 1px solid var(--border);
  font-size: .86rem; line-height: 1.45; color: var(--muted);
}
.tabell-rull th { color: var(--text); font-weight: 600; white-space: nowrap; }

/* Kortet med en handling som ikke kan angres. Kanten er dempet, ikke rød:
   den skal si «her bor det noe endelig», ikke rope hver gang fana åpnes. */
.fare-kort { border-color: var(--danger-soft); }

/* ============================ læring ============================

   Læringsportalen deler kortene, listene og merkene med resten av appen.
   Det som er eget her er tre ting: fremdriftsstolpen, spørsmålsavviklingen
   og fasitgjennomgangen.

   Fargene kommer fra temavariablene, aldri som faste verdier — de seks
   temaene skifter både bakgrunn og aksent, og en hardkodet grønn ville sett
   riktig ut i ett av dem. */

.lp-stolpe {
  display: block;
  height: 6px;
  border-radius: 999px;
  background: var(--surface-inset);
  overflow: hidden;
}
.lp-stolpe i {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--accent);
  transition: width .3s ease;
}

.lp-kort-tall { margin-top: 12px; }
.lp-kort-tekst {
  display: block;
  margin-top: 7px;
  font-size: .78rem;
  color: var(--muted);
}
.lp-fotnote { margin-top: 16px; font-size: .8rem; line-height: 1.5; }

/* ---- oversikten på kurssiden ---- */

.lp-oversikt-tall {
  display: flex;
  flex-wrap: wrap;
  gap: 22px;
  margin-bottom: 14px;
}
.lp-oversikt-tall > div { display: flex; flex-direction: column; }
.lp-oversikt-tall b { font-size: 1.5rem; line-height: 1.1; }
.lp-oversikt-tall span { font-size: .78rem; color: var(--muted); margin-top: 2px; }
.lp-oversikt-knapper {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: 16px;
}
.lp-paagaar { align-items: center; }
.lp-paagaar .btn { flex: none; }

/* ---- lister av emner, forsøk og filer ---- */

.lp-liste { padding: 4px 0; }
.lp-linje {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 11px 16px;
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid var(--border);
}
.lp-liste > .lp-linje:last-child { border-bottom: 0; }
a.lp-linje:hover { background: var(--surface-2); }
.lp-linje b { display: block; font-size: .92rem; font-weight: 600; }

/* «Temahefte 01» over emnenavnet. En overskrift over overskriften, ikke et
   merke ved siden av: linja har allerede opptil fire merker til høyre, og et
   femte hadde gjort nummeret til det minst synlige av dem. Her leses det
   først, som på skillearket i permen. */
.lp-hefte {
  display: block;
  margin-bottom: 1px;
  font-size: .7rem;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--muted);
}
a.lp-linje:hover .lp-hefte { color: var(--accent); }

/* Gruppenavnet over en emneliste — «Redskapsemner», «Grunnlagsemner». Den
   står mellom seksjonsoverskrifta «Emner» og kortet, og skal derfor være
   tydelig mindre enn den: to overskrifter i samme vekt over hverandre leses
   som to seksjoner, og det er én. */
.lp-gruppe {
  margin: 14px 2px 6px;
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .03em;
  text-transform: uppercase;
  color: var(--muted);
}
#lpEmner > .lp-gruppe:first-child { margin-top: 0; }
.page-head .lp-hefte { margin-bottom: 3px; font-size: .74rem; }

/* Veien ut av et emne skal ikke ligge fem tusen ord opp. Lenka kleber like
   under toppmenyen — derfor `--topbar-h` her og ikke et tall: to steder som
   vet hvor toppmenyen slutter er ett for mye.

   Den ligger utenfor `page-head` i markupen, fordi en sticky bare kleber
   innenfor sin egen forelder. Bakgrunnen er den samme uklare flaten som
   toppmenyen har, ellers ville figurer og tabeller rullet synlig under
   teksten i lenka. */
.lp-tilbakelinje {
  position: sticky;
  top: calc(var(--topbar-h) + env(safe-area-inset-top, 0px));
  z-index: 20;
  margin: -22px calc(clamp(14px, 3vw, 26px) * -1) 10px;
  padding: 10px clamp(14px, 3vw, 26px) 8px;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: saturate(180%) blur(14px);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
}
.lp-tilbakelinje .tilbake { margin-bottom: 0; }

.lp-emne-sub {
  display: block;
  margin-top: 2px;
  font-size: .79rem;
  color: var(--muted);
  line-height: 1.35;
}
.lp-emne-ikon {
  flex: none;
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: var(--r-sm);
  background: var(--surface-2);
  color: var(--muted);
}
a.lp-linje:hover .lp-emne-ikon { background: var(--accent-soft); color: var(--accent); }

/* ---- avviklingen av et forsøk ---- */

.lp-topp {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 9px;
}
.lp-teller { font-size: .82rem; color: var(--muted); }
.lp-timer {
  font-variant-numeric: tabular-nums;
  font-size: .85rem;
  font-weight: 640;
  padding: 3px 10px;
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--muted);
}
/* Under fem minutter igjen. Egen klasse og ikke bare en farge: fargen alene
   er ikke lesbar for alle, så merket bytter også bakgrunn og vekt. */
.lp-timer.knapp { background: var(--warn-soft); color: var(--warn); font-weight: 700; }

.lp-strip {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  margin-bottom: 14px;
}
.lp-prikk {
  width: 13px;
  height: 13px;
  padding: 0;
  border-radius: 50%;
  border: 1.5px solid var(--border-strong);
  background: transparent;
  cursor: pointer;
}
.lp-prikk:hover { border-color: var(--accent); }
.lp-prikk.gjort { background: var(--accent-soft); border-color: var(--accent); }
.lp-prikk.na { background: var(--accent); border-color: var(--accent); transform: scale(1.25); }

.lp-sporsmal h2 { font-size: 1.02rem; line-height: 1.45; margin: 0 0 4px; }
.lp-alter { display: flex; flex-direction: column; gap: 8px; margin-top: 14px; }
.lp-alt {
  display: flex;
  align-items: flex-start;
  gap: 11px;
  width: 100%;
  padding: 12px 14px;
  text-align: left;
  font-size: .9rem;
  line-height: 1.45;
  color: var(--text);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  cursor: pointer;
}
.lp-alt:hover { border-color: var(--border-strong); }
.lp-alt:disabled { cursor: default; }
.lp-alt-boks {
  flex: none;
  width: 17px;
  height: 17px;
  margin-top: 1px;
  border-radius: 50%;
  border: 2px solid var(--border-strong);
}
.lp-alt-boks.flere { border-radius: 4px; }
.lp-alt.valgt { border-color: var(--accent); background: var(--accent-soft); }
.lp-alt.valgt .lp-alt-boks { border-color: var(--accent); background: var(--accent); }
/* Etter at svaret er gitt: riktig og feil markeres begge med kant og
   bakgrunn, ikke bare med farge. */
.lp-alt.riktig { border-color: var(--ok); background: var(--ok-soft); }
.lp-alt.riktig .lp-alt-boks { border-color: var(--ok); background: var(--ok); }
.lp-alt.feil { border-color: var(--danger); background: var(--danger-soft); }
.lp-alt.feil .lp-alt-boks { border-color: var(--danger); background: var(--danger); }
.lp-tilbake { margin-top: 14px; align-items: flex-start; }

.lp-fot {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 16px;
}

/* ---- resultatet og gjennomgangen ---- */

.lp-resultat { display: flex; align-items: center; gap: 18px; }
.lp-resultat.ok { border-color: var(--ok); }
.lp-resultat.bad { border-color: var(--danger); }
.lp-res-tall {
  font-size: 2.4rem;
  font-weight: 700;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.lp-resultat.ok .lp-res-tall { color: var(--ok); }
.lp-resultat.bad .lp-res-tall { color: var(--danger); }
.lp-res-tall em { font-size: 1rem; font-style: normal; margin-left: 2px; }
.lp-resultat b { display: block; font-size: .95rem; }

.lp-fasit { margin-bottom: 12px; }
.lp-fasit-hode { display: flex; align-items: flex-start; gap: 10px; }
.lp-fasit-hode b { font-size: .93rem; line-height: 1.45; }
.lp-nr {
  flex: none;
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  font-size: .74rem;
  font-weight: 700;
  background: var(--surface-2);
  color: var(--muted);
}
.lp-nr.ok { background: var(--ok-soft); color: var(--ok); }
.lp-nr.bad { background: var(--danger-soft); color: var(--danger); }
.lp-fasit-alt { list-style: none; margin: 11px 0 0; padding: 0 0 0 34px; }
.lp-fasit-alt li {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding: 6px 10px;
  margin-bottom: 5px;
  font-size: .86rem;
  line-height: 1.4;
  border-radius: var(--r-sm);
  border: 1px solid transparent;
  color: var(--muted);
}
.lp-fasit-alt li > span { flex: 1; }
/* Merkelappen sier med ord det fargen sier med farge. Uten den er «ditt
   svar» og «fasit» to nyanser for den som ikke skiller rødt fra grønt. */
.lp-fasit-alt li em {
  flex: none;
  font-style: normal;
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  white-space: nowrap;
}
.lp-fasit-alt li.valgt { border-color: var(--border-strong); color: var(--text); }
.lp-fasit-alt li.riktig { background: var(--ok-soft); color: var(--ok); border-color: transparent; }
.lp-fasit-alt li.feil { background: var(--danger-soft); color: var(--danger); border-color: transparent; }
.lp-forklaring {
  margin: 10px 0 0 34px;
  font-size: .85rem;
  line-height: 1.55;
  color: var(--muted);
}

.lp-emnefot-rad {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 12px;
}
.lp-emnefot-rad:last-child { margin-bottom: 0; }

@media (max-width: 640px) {
  .lp-oversikt-tall { gap: 16px; }
  .lp-oversikt-tall b { font-size: 1.25rem; }
  .lp-linje { padding: 11px 13px; gap: 9px; }
  .lp-fasit-alt, .lp-forklaring { padding-left: 0; margin-left: 0; }
}

/* Rollevelgeren på et kurs med flere nivåer. Den står mellom overskriften og
   lista fordi den styrer hva lista viser — ikke i toppmenyen, der den ville
   sett ut som en modus for hele portalen. */
.lp-rollerad {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin: -4px 0 12px;
}
.lp-rollerad .hint { margin: 0; }

/* Undertittelen til en nivåseksjon i læringsportalen. Samme plass og samme
   dempede vekt som i verktøykatalogen — de to sidene er bygget likt, og en
   bruker som kjenner den ene skal kjenne igjen den andre. */
.lp-kat-sub { margin: -6px 0 12px; font-size: .84rem; }

/* ============================ tegninger ============================

   Rutenettet er modulen. Alt annet her er i tjeneste for at tjue tegninger
   skal kunne ligge på skjermen samtidig, og at det skal være tydelig hvilken
   man skal trykke på.

   **Flisene klipper ingenting.** `object-fit: contain`, ikke `cover`. Et
   fotoalbum tåler en beskåret flis; en tegning gjør det ikke — det er
   nettopp kantene, solen oppe i hjørnet og navnet nederst til høyre, som
   ryker først når man klipper til et kvadrat. Prisen er at flisene får ulik
   mengde luft rundt seg, og det er en pris verdt å betale.

   **Bunnen er `--surface` og ikke hvit.** Et innskannet ark er hvitt
   uansett, så det ser likt ut der — men et *fotografi* av en tegning har
   mørke kanter, og på en hvit flate ville det stått som et bilde limt på et
   ark. Med temaets egen flate ligger begge deler i samme drakt. */

.tg-rutenett {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 14px;
}

.tg-flis {
  display: flex;
  flex-direction: column;
  gap: 7px;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  cursor: pointer;
  text-align: left;
  font: inherit;
}

.tg-ark {
  display: flex;
  align-items: center;
  justify-content: center;
  /* Kvadratisk ramme, uansett hva som ligger i den. Et rutenett der hver
     rute har sin egen høyde er ikke et rutenett, det er en stabel — og
     `contain` inni gjør at ingenting av tegningen går tapt likevel. */
  aspect-ratio: 1;
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  box-shadow: var(--shadow);
  transition: transform .12s ease, border-color .12s ease;
}
.tg-flis:hover .tg-ark,
.tg-flis:focus-visible .tg-ark {
  transform: translateY(-2px);
  border-color: var(--accent);
}
.tg-ark img { width: 100%; height: 100%; object-fit: contain; display: block; }

.tg-flis-tekst {
  font-size: .8rem;
  color: var(--muted);
  line-height: 1.35;
  /* To linjer og så avkortet. En tittel som får vokse fritt skyver
     nabokolonnene ut av takt, og da står rutenettet skjevt. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* HEIC og TIFF: fila ligger trygt, men ingen nettleser tegner den. Flisa
   sier det med ord i stedet for å bli det brutte bildet den skal hindre. */
.tg-uvisbar {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 14px;
  text-align: center;
  color: var(--faint);
  font-size: .78rem;
  line-height: 1.4;
}
.tg-uvisbar.stor { font-size: .88rem; max-width: 30ch; }

/* Antallet i årsoverskriften. Står foran streken, ikke etter — se
   `.section-title::after`, som er selve streken.

   Bare et tall, uten pille rundt. Pillen var der først, med `--surface-2` som
   bunn, og den forsvant helt i de lyse temaene fordi flaten der ligger tett
   opptil bakgrunnen: samme element med en synlig form i mørkt tema og ingen
   form i lyst. Et tall som ser likt ut overalt er bedre enn en form som bare
   halvparten ser. */
.tg-antall {
  font-size: .74rem;
  font-weight: 600;
  color: var(--faint);
  letter-spacing: 0;
}

/* Velgeren: ett kort per person, med den nyeste tegningen som forside. */
.tg-personer {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: 14px;
}
.tg-person {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow);
  text-decoration: none;
  color: var(--text);
}
.tg-person:hover { border-color: var(--accent); }
.tg-person-bilde {
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 4 / 3;
  margin-bottom: 8px;
  overflow: hidden;
  border-radius: var(--r-sm);
  background: var(--surface-2);
  color: var(--faint);
}
.tg-person-bilde img { width: 100%; height: 100%; object-fit: contain; }
.tg-person-navn { font-weight: 620; font-size: .95rem; }
.tg-person-tall { font-size: .8rem; color: var(--muted); }

/* ---- viseren ---- */

/* Viseren fyller hele det store vinduet. `.modal.stor` har fast høyde (se
   der), og uten at innholdet får vokse inn i den, sto bildet klemt i toppen
   med tre hundre piksler tom flate under bildeteksten. */
.tg-viser { display: flex; flex-direction: column; min-height: 0; }
.modal.stor .modal-body > .tg-viser { flex: 1; }

.tg-viser-flate {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Bildet tar plassen som blir til overs når bildeteksten har fått sin —
     ikke en høyde regnet i vh. Vinduet har allerede et tak, og to tak som
     ikke kjenner hverandre gir enten en tom stripe eller en tegning som må
     rulles for å ses. */
  flex: 1;
  min-height: 0;
  background: var(--surface-2);
  overflow: hidden;
}
.tg-viser-flate img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  display: block;
}

.tg-bla {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: 999px;
  border: 1px solid var(--border);
  /* Halvgjennomsiktig flate og ikke en heldekkende: knappene ligger oppå
     tegningen, og en tett sirkel midt på en A4 dekker gjerne et ansikt. */
  background: color-mix(in srgb, var(--surface) 82%, transparent);
  color: var(--text);
  cursor: pointer;
  backdrop-filter: blur(3px);
}
.tg-bla:hover { border-color: var(--accent); }
.tg-bla.f { left: 10px; }
.tg-bla.n { right: 10px; }

/* Bildeteksten. Egen innramming fordi `.modal.stor .modal-body` har
   `padding: 0` — den er satt for at et dokument skal kunne gå helt ut i
   kanten, og uten dette lå teksten klistret til vindusrammen. */
.tg-viser-under {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  padding: 14px 20px;
  border-top: 1px solid var(--border);
}
.tg-viser-knapper { display: flex; gap: 8px; flex-wrap: wrap; }
.tg-notat {
  margin-top: 6px;
  font-size: .88rem;
  line-height: 1.5;
  color: var(--text-muted);
}
.tg-teller { margin-top: 6px; }

@media (max-width: 640px) {
  /* Mindre fliser, men fortsatt minst to i bredden — én tegning per rad er
     en stabel å rulle gjennom, og det er nettopp oversikten man kom for. */
  .tg-rutenett { grid-template-columns: repeat(auto-fill, minmax(118px, 1fr)); gap: 10px; }
  .tg-personer { grid-template-columns: repeat(auto-fill, minmax(132px, 1fr)); gap: 10px; }
  .tg-viser-under { padding: 12px 14px; }
  .tg-bla { width: 34px; height: 34px; }
}

/* ============================ Hovedprosjektet ============================
   Invitasjonen. Alt annet — startsiden, gruppa, lenkene og selve prosjektet —
   har sitt eget stilark i app/hovedprosjekt/felles/: det er en egen side. */
.hp-ico {
  width: 44px; height: 44px; flex: none; display: grid; place-items: center;
  border-radius: var(--r-md); background: var(--accent-soft); color: var(--accent);
}
.auth-melding {
  color: var(--text); background: var(--accent-soft);
  padding: 10px 12px; border-radius: var(--r-md); line-height: 1.45;
}

/* ============================ meldinger ============================

   Én side, to flater: samtalene i en kolonne til venstre, den åpne samtalen
   på resten. Fem valg er verdt å kjenne:

   **Siden fyller vinduet, den ruller ikke med.** `.meld-side` er `100dvh`
   minus toppmenyen, og det er *flaten* som ruller — ikke dokumentet. Det er
   motsatt av alle de andre sidene i portalen, og grunnen er at skrivefeltet
   skal stå stille nederst mens meldingene ruller bak det. `dvh` og ikke `vh`
   fordi adresselinja på mobil spiser av `vh` og gjør feltet utilgjengelig
   akkurat når tastaturet er oppe.

   **Under 900 px er det én flate om gangen.** Lista når ingenting er valgt,
   samtalen når noe er — styrt av `.uten-valg`/`.med-valg` på selve siden, og
   ikke av to ulike render-funksjoner. Tilbakepila i samtalehodet finnes bare
   i den bredden; på en bred skjerm går man tilbake ved å velge noe annet.

   **Boblene farges av avsenderen, ikke av retningen alene.** Mine er
   `--accent-soft` med temaets tekstfarge, ikke fylt aksent med hvit tekst:
   `--accent` er en sterk flate i flere av temaene, og en hel samtale i den
   blir en vegg. Den svake flaten skiller like tydelig, og den holder i alle
   seks temaene — også de lyse, der en fylt aksentboble med hvit tekst ligger
   nærmest kontrastgrensa.

   **Merket i menylinja er et tall, ikke en prikk.** «Det står noe nytt» er
   ikke nok når man har ti samtaler; «3» sier om det er verdt å åpne nå.

   **En valgt rad har en strek, ikke bare en flate.** Samme grunn som
   skravuren i samværsplanen: `--accent-soft` alene ligger for tett på
   `--surface-2` i flere temaer til å bære «dette er den du står i». */

.meld-side {
  display: grid;
  grid-template-columns: minmax(260px, 340px) 1fr;
  gap: 0;
  /* `flex: none` og ikke bare en høyde. `.page` er et flex-barn med
     `flex: 1`, altså `flex-basis: 0` — og da er det flex-algoritmen og ikke
     `height` som setter hovedstørrelsen. Uten dette vokste flaten til å romme
     hele samtalen, dokumentet ble tre tusen piksler høyt, og både lista og
     skrivefeltet rullet ut av syne. Det så ut som en tom venstrekolonne. */
  flex: none;
  min-height: 0;
  /* Toppmenyen tar sin høyde, siden får resten og ruller ikke selv.
     `--topbar-h` og ikke et tall: to steder som vet hvor høy menyen er, er
     ett for mye — samme grunn som dropdownen under den bruker den. */
  height: calc(100dvh - var(--topbar-h) - env(safe-area-inset-top, 0px));
  max-width: none;
  padding: 0;
  overflow: hidden;
}

.meld-kolonne {
  display: flex;
  flex-direction: column;
  min-height: 0;
  border-right: 1px solid var(--border);
  overflow-y: auto;
  scrollbar-width: thin;
}

.meld-kolonne-hode {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 16px 14px 10px;
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--bg);
}
.meld-kolonne-hode h1 { font-size: 1.15rem; margin: 0; }
.meld-kolonne-tom { padding: 6px 12px; }

.meld-bolk {
  padding: 10px 14px 6px;
  font-size: .74rem;
  font-weight: 650;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted);
}

.meld-liste {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 0 8px 8px;
}

.meld-rad {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 9px 10px;
  border-radius: var(--r-md);
  border-left: 3px solid transparent;
  color: inherit;
  text-decoration: none;
  transition: background .12s ease;
}
.meld-rad:hover { background: var(--surface); }
.meld-rad.on { background: var(--surface-2); border-left-color: var(--accent); }
.meld-rad.ulest .meld-rad-navn { font-weight: 700; }
.meld-rad.ulest .meld-rad-forhand { color: var(--text); }

.meld-rad-tekst { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.meld-rad-navn { font-weight: 600; font-size: .9rem; }
/* Én linje, og resten klippes. En forhåndsvisning som bretter seg over tre
   linjer gjør lista til en samling kort, og da forsvinner oversikten som er
   hele poenget med en innboks. */
.meld-rad-forhand {
  font-size: .8rem;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.meld-rad-hoyre {
  display: flex; flex-direction: column; align-items: flex-end; gap: 4px;
  flex: none;
}
.meld-tid { font-size: .7rem; color: var(--muted); white-space: nowrap; }

.meld-merke {
  min-width: 19px; padding: 1px 6px;
  border-radius: 999px;
  background: var(--accent); color: var(--accent-contrast);
  font-size: .7rem; font-weight: 700; text-align: center;
}

.meld-gruppeavatar {
  background: var(--accent-soft) !important;
  color: var(--accent);
  display: grid; place-items: center;
}

/* ---- knappen i menylinja ---- */

.meldingknapp { position: relative; }
.meldingknapp.on { color: var(--accent); background: var(--accent-soft); }
.meldingknapp-merke {
  position: absolute;
  top: -3px; right: -3px;
  min-width: 16px; padding: 0 4px;
  border-radius: 999px;
  background: var(--accent); color: var(--accent-contrast);
  font-size: .64rem; font-weight: 700; line-height: 1.6; text-align: center;
  /* Ringen skiller merket fra ikonet under når de overlapper. */
  box-shadow: 0 0 0 2px var(--bg);
}

/* ---- samtaleflaten ---- */

.meld-samtale {
  display: flex;
  flex-direction: column;
  min-height: 0;
  min-width: 0;
}

.meld-hode {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 12px 18px;
  border-bottom: 1px solid var(--border);
  flex: none;
}
.meld-hode h2 { font-size: 1rem; margin: 0; }
.meld-hode p {
  font-size: .78rem; color: var(--muted); margin: 2px 0 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* Bare i én flate om gangen — på bred skjerm går man tilbake ved å velge
   noe annet, og en pil som ikke fører noe sted er en pil man mister tillit
   til. */
.meld-tilbake { display: none; color: var(--muted); }

.meld-foresporsel {
  margin: 12px 18px 0;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: var(--r-md);
  background: var(--surface);
  flex: none;
  /* Teksten er tre setninger, og en linje på tusen piksler leses ikke. */
  max-width: 720px;
}
.meld-foresporsel h3 { font-size: .95rem; margin: 0 0 4px; }
.meld-foresporsel p {
  font-size: .84rem; line-height: 1.5; color: var(--muted); margin: 0 0 10px;
}

.meld-flate {
  display: flex;
  flex-direction: column;
  gap: 7px;
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 14px 18px;
  scrollbar-width: thin;
}

.meld-dag {
  align-self: center;
  margin: 8px 0 4px;
  padding: 2px 10px;
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--muted);
  font-size: .72rem;
}

.meld-boble {
  display: flex;
  flex-direction: column;
  gap: 2px;
  align-self: flex-start;
  max-width: min(72%, 560px);
  padding: 8px 11px;
  border: 1px solid var(--border);
  border-radius: 14px 14px 14px 4px;
  background: var(--surface);
  font-size: .9rem;
  line-height: 1.45;
}
.meld-boble.min {
  align-self: flex-end;
  border-radius: 14px 14px 4px 14px;
  background: var(--accent-soft);
  border-color: color-mix(in srgb, var(--accent) 34%, transparent);
}
.meld-boble.trukket { color: var(--muted); }
.meld-avsender { font-size: .73rem; font-weight: 650; color: var(--accent); }
.meld-tekst { overflow-wrap: anywhere; }
.meld-klokke { align-self: flex-end; font-size: .68rem; color: var(--muted); }

.meld-lest {
  align-self: flex-end;
  display: inline-flex; align-items: center; gap: 4px;
  margin-top: 2px;
  font-size: .72rem; color: var(--muted);
}

/* Knappen som henter historikken. Den står *i* flaten og ikke over den, så
   den ruller opp og ut av veien når du har hentet det du lette etter. */
.meld-eldre { align-self: center; margin-bottom: 6px; }

.meld-skriv {
  display: flex;
  align-items: flex-end;
  gap: 8px;
  flex: none;
  margin: 0 18px 16px;
  padding: 8px;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface);
}
.meld-skriv textarea {
  flex: 1;
  /* Global `textarea`-regel gir en min-høyde som er riktig for et skjemafelt
     og feil her: skrivefeltet skal starte på én linje og vokse med teksten. */
  min-height: 0;
  border: 0;
  background: none;
  color: var(--text);
  font: inherit;
  font-size: .92rem;
  resize: none;
  padding: 6px 4px;
  max-height: 160px;
}
.meld-skriv textarea:focus { outline: none; }
.meld-skriv .iconbtn.send { color: var(--accent); flex: none; }

/* Flaten når ingen samtale er valgt. Den skal si hva stedet er, ikke stå tom
   og vente — en blank halvside leses som at noe ikke lastet. */
.meld-velkomst {
  margin: auto;
  padding: 24px;
  text-align: center;
  max-width: 380px;
}
.meld-velkomst-ico {
  display: grid; place-items: center;
  width: 62px; height: 62px; margin: 0 auto 14px;
  border-radius: 50%;
  background: var(--accent-soft); color: var(--accent);
}
.meld-velkomst h2 { font-size: 1.05rem; margin: 0 0 6px; }
.meld-velkomst p {
  font-size: .88rem; line-height: 1.55; color: var(--muted); margin: 0 0 14px;
}

/* Aria-knappen og chatten deler nederste høyre hjørne, og de kan ikke begge
   få det.

   Knappen er `position: fixed` nederst til høyre. Alle andre sider har
   `padding-bottom: 90px` og går klar; denne fyller vinduet, så knappen lå
   rett oppå send-knappen — den ene kontrollen siden faktisk er til for. Å
   flytte knappen opp løste det ene og lagde det andre: da lå den over den
   nyeste meldingen, som er den man helst vil lese.

   Derfor viker *skrivefeltet* i stedet, på skjermer som har plass til det.
   Knappen blir stående der folk vet den er, og boblene ligger over feltet og
   altså klar av den. På en telefon finnes ikke den plassen, og der er svaret
   et annet — se mediespørringen lenger ned. */
@media (min-width: 901px) {
  body:has(.meld-side) .meld-skriv { margin-right: 86px; }
}

/* ---- velgeren ---- */

.meld-brikker { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px; }
.meld-brikke {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 4px 9px;
  border: 1px solid color-mix(in srgb, var(--accent) 40%, transparent);
  border-radius: 999px;
  background: var(--accent-soft);
  color: var(--text);
  font: inherit; font-size: .82rem;
  cursor: pointer;
}

.meld-velgliste { display: flex; flex-direction: column; gap: 4px; }

.meld-velg {
  display: flex; align-items: center; gap: 10px;
  width: 100%;
  padding: 7px 10px;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.meld-velg:hover { background: var(--surface-2); }
.meld-velg.statisk { cursor: default; }
.meld-velg.statisk:hover { background: var(--surface); }
.meld-velg-navn { font-size: .89rem; font-weight: 560; display: block; }
/* Haken vises bare når raden er valgt. Å ha den der grå hele tiden leses som
   en avkryssingsboks som ikke virker. */
.meld-velg .meld-hake { opacity: 0; color: var(--accent); flex: none; }
.meld-velg.on { border-color: var(--accent); background: var(--accent-soft); }
.meld-velg.on .meld-hake { opacity: 1; }

/* ---- én flate om gangen ---- */

@media (max-width: 900px) {
  .meld-side { grid-template-columns: 1fr; }
  .meld-side.med-valg .meld-kolonne { display: none; }
  .meld-side.uten-valg .meld-samtale { display: none; }
  .meld-kolonne { border-right: 0; }
  .meld-tilbake { display: inline-flex; }
  .meld-boble { max-width: 86%; }
  .meld-hode, .meld-flate { padding-left: 14px; padding-right: 14px; }
  .meld-skriv { margin-left: 14px; margin-right: 14px; }
}

@media (max-width: 960px) {
  /* Bunnmenyen ligger over siden, så flaten må slutte over den — ellers
     havner skrivefeltet under tabbaren akkurat når man skal bruke det. */
  .meld-side {
    height: calc(100dvh - var(--topbar-h) - env(safe-area-inset-top, 0px)
                 - 64px - env(safe-area-inset-bottom));
    padding-bottom: 0;
  }
  /* På en telefon er det ikke plass til at skrivefeltet viker — 86 px av 390
     er en fjerdedel av linja. Og en knapp som flyttes opp, legger seg over
     den nyeste meldingen i stedet.

     Derfor er Aria borte mens en samtale står åpen, og bare da: i lista er
     knappen der som ellers, ett trykk unna. Det er en ærligere avveining enn
     en flytende knapp som dekker det man kom for å lese — og den samme
     avveiningen Messenger selv gjør på en liten skjerm. */
  body:has(.meld-side.med-valg) .aria-fab,
  body:has(.meld-side.med-valg) .aria-panel { display: none; }
}

/* ============================ Nettskraping ============================

   Benken for crawlerne. Blokkene er kort nedover siden, i den rekkefølgen
   serveren sendte dem — en blokk er ett spørsmål, og de leses ovenfra.

   `.crawl-kode` har `max-height` og `.crawl-tekst` har det ikke, og det er
   ikke inkonsekvens: teksten er svaret man leter etter og skal kunne leses i
   sidens egen rulling, mens rå HTML er noe man ser *litt* av for å bekrefte at
   den kom — femti tusen tegn markup som skyver resten av siden ut av syne er
   ikke til hjelp. Samme avveining som `.opptak-tekst` gjør motsatt vei, og av
   samme grunn: hva er flata til for. */

.crawl-blokk { margin-bottom: 14px; }
.crawl-om { margin-bottom: 14px; }
.crawl-tittel { font-size: .95rem; font-weight: 640; margin-bottom: 8px; }
.crawl-avsnitt { font-size: .88rem; line-height: 1.6; }
.crawl-avsnitt.bad { color: var(--danger); }
.crawl-note {
  font-size: .8rem; line-height: 1.55; color: var(--muted);
  margin: 6px 0 10px;
}
.crawl-note:last-child { margin-bottom: 0; }

/* Nøkkeltallene. `auto-fit` og ikke et fast antall kolonner: en motor kan
   sende tre tall og en annen seks, og rekka skal ikke ha et hull på en
   telefon. */
.crawl-tall {
  display: grid; gap: 10px 18px;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
}
.crawl-tall > div { min-width: 0; }
.crawl-tall .lbl {
  display: block; font-size: .7rem; font-weight: 640; letter-spacing: .05em;
  text-transform: uppercase; color: var(--faint); margin-bottom: 2px;
}
.crawl-tall b {
  display: block; font-size: .9rem; font-weight: 600;
  overflow-wrap: anywhere;
}

.crawl-treff { display: grid; gap: 8px; }
.crawl-treff li {
  display: grid; gap: 2px;
  padding: 9px 11px; border-radius: var(--r-sm);
  background: var(--surface-2); border: 1px solid var(--border);
}
.crawl-linje {
  font-size: .68rem; font-weight: 700; letter-spacing: .05em;
  text-transform: uppercase; color: var(--faint);
}
.crawl-bit { font-size: .87rem; line-height: 1.6; overflow-wrap: anywhere; }
.crawl-bit mark {
  background: var(--accent-soft); color: var(--accent);
  border-radius: 3px; padding: 0 2px; font-weight: 640;
}

.crawl-tekst {
  white-space: pre-wrap; overflow-wrap: break-word;
  font-size: .89rem; line-height: 1.65;
}
.crawl-kode {
  white-space: pre-wrap; overflow-wrap: anywhere;
  max-height: 420px; overflow-y: auto;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .78rem; line-height: 1.55;
  padding: 11px 13px; border-radius: var(--r-sm);
  background: var(--surface-2); border: 1px solid var(--border);
}

.crawl-lenker { display: grid; gap: 7px; }
.crawl-lenker li { display: grid; gap: 1px; min-width: 0; }
.crawl-lenker a { font-size: .87rem; font-weight: 560; }
.crawl-url {
  font-size: .72rem; color: var(--faint);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Fanen til en motor som ikke kan kjøre. Prikken er fylt eller en ring, ikke
   bare en annen farge — se kommentaren over crawlFane() i app.js. */
.tabs button.av { opacity: .62; }
/* …men ikke den du står i. En fane som er valgt og samtidig nedtonet leses
   som at siden ikke svarte, og det er nettopp den fanen som har en hel
   forklaring å vise fram. Ringen sier fortsatt at motoren ikke kan kjøre. */
.tabs button.av.on { opacity: 1; }
.crawl-prikk {
  display: inline-block; width: 7px; height: 7px; border-radius: 50%;
  border: 1.5px solid currentColor; margin-right: 2px; vertical-align: 1px;
}
.crawl-prikk.pa { background: currentColor; }

/* Hvor en modul er *tatt i bruk* — Admin → Moduler.

   Bolken er en <details> og ikke alltid åpen: de fleste modulene er ikke
   tildelt noe sted, og tolv avkryssinger per modul ville gjort siden til en
   vegg. Den står åpen når noe er huket av, for da er det en opplysning. */
/* `.modul-felt` er et rutenett med etiketten i venstre kolonne. En
   <details> har summary, hint og bolker som *søsken*, så de havnet i
   rutenettets celler og «Tatt i bruk» sto midt på siden av innholdet. Her
   er det blokkflyt, og etiketten ligger inne i summary. */
.omrade-felt { display: block; padding: 8px 0 2px; }
.omrade-felt > summary {
  display: flex; align-items: baseline; gap: 10px; cursor: pointer;
  padding: 2px 0; list-style: none;
}
.omrade-felt > summary::-webkit-details-marker { display: none; }
.omrade-felt > summary::after {
  content: '▸'; color: var(--muted); font-size: 11px; margin-left: auto;
}
.omrade-felt[open] > summary::after { content: '▾'; }
.omrade-tall { font-size: 12px; color: var(--muted); }
.omrade-felt .hint { margin: 6px 0 12px; font-size: .8rem; }
.omrade-bolk { margin-bottom: 10px; }
.omrade-bolk .lbl { display: block; margin-bottom: 5px; }
.omrade-valg { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 4px 12px; }
/* Én sammenleggbar bolk per kurs inne i «Enkeltfag». Summary-en er lukket
   til noe er huket av, så de 48 emnene ikke er en vegg; tallet til høyre er
   det som gjør en lukket bolk verdt å lukke — du ser at det står noe i den
   uten å åpne den. */
.omrade-gruppe { border-top: 1px solid var(--line); }
.omrade-gruppe > summary {
  display: flex; align-items: center; gap: 8px; cursor: pointer;
  padding: 6px 2px; font-size: 13px; color: var(--fg); list-style: none;
}
.omrade-gruppe > summary::-webkit-details-marker { display: none; }
.omrade-gruppe > summary::before {
  content: ''; width: 0; height: 0; flex: none;
  border-left: 5px solid currentColor;
  border-top: 4px solid transparent; border-bottom: 4px solid transparent;
  opacity: .55; transition: transform .12s ease;
}
.omrade-gruppe[open] > summary::before { transform: rotate(90deg); }
.omrade-gruppe > summary .omrade-tall { margin-left: auto; }
.omrade-gruppe > .omrade-valg { padding: 2px 0 8px 13px; }
.omrade-kryss { display: flex; align-items: flex-start; gap: 8px; font-size: 13px; padding: 3px 0; cursor: pointer; }
.omrade-kryss input { margin-top: 2px; flex: none; }
.omrade-kryss small { display: block; color: var(--muted); font-size: 11.5px; }

/* ============================ regelverk ============================ */

/* Forskriftstekstene (app/regelverk.py). Teksten er kildens HTML vasket til
   et lite sett tagger, så alt den har av form kommer herfra — tabellene i
   § 14-2 og § 14-3 er det viktigste: det er der tallene står. */
.rv-kilde .rv-ikon {
  width: 40px; height: 40px; flex: none; display: grid; place-items: center;
  border-radius: var(--r-md); background: var(--accent-soft); color: var(--accent);
}
.rv-kilde.ulest { border-color: var(--warn); }
.rv-meta {
  display: flex; flex-wrap: wrap; gap: 6px 18px; margin-top: 10px;
  font-size: .82rem; color: var(--muted);
}
.rv-meta span { display: inline-flex; align-items: center; gap: 5px; }
.rv-feil {
  margin-top: 10px; padding: 8px 12px; border-radius: var(--r-sm);
  background: var(--danger-soft); color: var(--danger); font-size: .84rem;
}
.rv-admin { justify-content: space-between; margin-bottom: 14px; flex-wrap: wrap; gap: 8px; }

.rv-verktoy {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: 10px; margin-bottom: 14px;
}
.rv-verktoy input[type=search] { flex: 1 1 220px; }
.rv-versjon { display: flex; flex-direction: column; gap: 4px; font-size: .78rem; color: var(--muted); }
.rv-versjon select { min-width: 200px; }
.rv-bryter { display: inline-flex; align-items: center; gap: 8px; font-size: .86rem; padding-bottom: 9px; }
.rv-sum { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-bottom: 16px; }

.rv-kap { font-size: 1.05rem; margin: 22px 0 10px; color: var(--muted); }
.rv-kap:first-child { margin-top: 0; }
.rv-del + .rv-del { margin-top: 12px; }
.rv-del .card-head h3 { font-size: 1rem; }
.rv-del.rv-endret { border-left: 3px solid var(--warn); }
.rv-del.rv-ny { border-left: 3px solid var(--ok); }
.rv-del.rv-fjernet { border-left: 3px solid var(--danger); }

.rv-tekst { font-size: .92rem; line-height: 1.6; }
.rv-tekst p, .rv-tekst .rv-ledd { margin: 0 0 10px; }
.rv-tekst .rv-ledd .rv-ledd { margin-bottom: 4px; }
.rv-tekst ol, .rv-tekst ul { margin: 4px 0 10px 22px; }
.rv-tekst li { margin: 3px 0; }
.rv-tekst h4 { font-size: .86rem; margin: 14px 0 6px; color: var(--accent); }
.rv-tekst table {
  width: 100%; border-collapse: collapse; margin: 8px 0 12px; font-size: .84rem;
}
.rv-tekst th, .rv-tekst td {
  padding: 6px 8px; border: 1px solid var(--border); vertical-align: top; text-align: left;
}
.rv-tekst th { background: var(--surface-inset); font-weight: 620; }
.rv-tekst caption { text-align: left; color: var(--muted); font-size: .8rem; padding: 4px 0; }
.rv-tekst a { color: var(--accent); text-decoration: underline; }
.rv-tekst img { max-width: 100%; height: auto; border-radius: var(--r-sm); }
/* DiBKs veiledning: egen boks, så forskrift og veiledning kan skilles på
   et blikk — det ene er krav, det andre er direktoratets lesning av dem. */
.rv-tekst .rv-veiledning {
  margin: 8px 0 14px; padding: 10px 14px; border-radius: var(--r-md);
  background: var(--surface-inset); border-left: 3px solid var(--accent);
}
.rv-tekst .rv-veiledning h4:first-child { margin-top: 0; }

/* Diffen: ordene som gikk ut og de som kom inn, i samme setning. `pre`
   fordi linjeskiftene i teksten er kildens egne ledd og tabellrader. */
.rv-diff {
  white-space: pre-wrap; font-family: inherit; font-size: .9rem; line-height: 1.6;
  margin: 0; padding: 0;
}
.rv-diff del { background: var(--danger-soft); color: var(--danger); text-decoration: line-through; border-radius: 3px; padding: 0 2px; }
.rv-diff ins { background: var(--ok-soft); color: var(--ok); text-decoration: none; border-radius: 3px; padding: 0 2px; font-weight: 600; }
.update-chip.rv-chip { background: var(--accent-soft); color: var(--accent); }
.update-chip.rv-chip .cnt { background: var(--accent); }

/* ============================ Dekk ============================ */

/* Raden er trykkflaten på begge flatene — markøren må si det, og
   tastaturfokus må kunne ses. `.rows.boxed > .rw:hover` gir bakgrunnen; det
   som manglet var at raden *ser* ut som noe man kan trykke på. */
.dekk-rad { cursor: pointer; }
.dekk-rad:focus-visible {
  outline: 2px solid var(--accent); outline-offset: -2px; border-radius: var(--r-sm);
}

/* En hintlinje med et ikon foran. `svg.ico` er `display: block` globalt, så
   et ikon limt inn i en <p> faller ned på sin egen linje — ikonet sto over
   teksten i stedet for foran den. Flex i stedet for å røre den globale
   regelen: den gjelder hundrevis av steder, og dette er ett av dem. */
.dekk-hint { display: flex; align-items: flex-start; gap: 6px; }
.dekk-hint svg { margin-top: 2px; }

/* Statusvelgeren i bestillingsvinduet. Den er `.tabs`, men står inne i et
   skjema og ikke øverst på en side, så den trenger mindre luft over seg. */
.dekk-statusvalg { margin-top: 2px; }

/* Statusfilteret i korthodet. `.card-head` er en flex-rad, og uten en
   bredde strakk nedtrekkslista seg over hele raden og dyttet «Ny» ut. */
.dekk-filter {
  flex: 0 0 auto; width: auto; min-width: 136px;
  padding: 7px 10px; font-size: .84rem;
  border-radius: var(--r-sm); border: 1px solid var(--border-strong);
  background: var(--surface); color: var(--text);
}

/* Kundens egne ord. Lesning og ikke et felt — en melding som kan rettes er
   en melding man ikke kan stole på neste gang man leser den. Formen sier
   det: innrykket kant som et sitat, og `pre-wrap` så linjeskiftene kunden
   skrev står der de ble skrevet. */
.dekk-melding {
  white-space: pre-wrap; overflow-wrap: anywhere;
  padding: 10px 12px; border-left: 3px solid var(--border-strong);
  background: var(--surface-2); border-radius: 0 var(--r-sm) var(--r-sm) 0;
  font-size: .88rem; line-height: 1.5;
}

@media (max-width: 560px) {
  /* På telefon får overskriften linja si, og filteret og «Ny» deler den
     neste. Alle tre på én rad klemte «Bestillinger» ned til «B» — `.grow`
     krymper, og en overskrift som krymper blir borte før knappen gjør det. */
  .dekk-hode .grow { flex: 1 1 100%; }
  .dekk-filter { flex: 1 1 auto; min-width: 0; }
}

/* ========================= hobbyregnskap =========================

   Siden til modulen Hobbyregnskap (`#/hobbyregnskap`). Formen følger av
   hva siden skal svare på: *hvor står jeg?* — ikke «hva har jeg ført».
   Tallene og grensene står derfor over postlista, og grensene er den eneste
   delen som har fått en egen visuell form. */

/* Tallrekka. Egen klasse og ikke `.admin-grid`, fordi boksene her har tre
   linjer — tallet, hva det er, og hvilken periode — mens admin-rutenettet
   har to. */
.hb-tall {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 12px; margin-bottom: 16px;
}
.hb-tall .stat-box small {
  display: block; margin-top: 4px;
  font-size: .7rem; letter-spacing: .06em; text-transform: uppercase;
  color: var(--muted); font-weight: 600;
}
.hb-tall .stat-box.good b { color: var(--ok); }
.hb-tall .stat-box.bad b { color: var(--danger); }
.hb-tall .stat-box.warn b { color: var(--warn); }

/* Grenselinja. **Søylen er ikke pynt.** «32 000 av 50 000» er et tall man må
   regne på; en søyle som er to tredeler full er noe man ser, og det er det
   som skal få noen til å gå og sjekke noe før grensen er passert. Derfor har
   linja også en kantstripe: en farge på et tall alene drukner blant fem
   andre tall. */
.hb-grenselinje {
  padding: 13px 0 13px 14px; border-left: 3px solid var(--border-strong);
  margin-bottom: 6px;
}
.hb-grenselinje:last-of-type { margin-bottom: 0; }
.hb-grenselinje.naermer { border-left-color: var(--warn); }
.hb-grenselinje.over { border-left-color: var(--danger); }
.hb-grensehode { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.hb-grensetall {
  font-size: .82rem; color: var(--muted); margin-top: 5px;
  font-variant-numeric: tabular-nums;
}
.hb-soyle {
  height: 7px; border-radius: 99px; background: var(--surface-inset);
  overflow: hidden; margin-top: 8px;
}
.hb-soyle i { display: block; height: 100%; background: var(--accent); border-radius: 99px; }
.hb-grenselinje.naermer .hb-soyle i { background: var(--warn); }
.hb-grenselinje.over .hb-soyle i { background: var(--danger); }
.hb-grenselinje .hint { display: block; margin-top: 7px; }
.badge.naermer { background: var(--warn-soft); color: var(--warn); }
.badge.over { background: var(--danger-soft); color: var(--danger); }

/* Motpartene under en grense som er per oppdragsgiver. Uten navnene er
   linja ubrukelig: det er hos *én* av dem man er over. */
.hb-motparter { list-style: none; margin: 9px 0 0; padding: 0; }
.hb-motparter li {
  display: flex; justify-content: space-between; gap: 12px;
  padding: 4px 0; font-size: .85rem; border-bottom: 1px solid var(--border);
}
.hb-motparter li:last-child { border-bottom: none; }
.hb-motparter li.over b { color: var(--danger); }
.hb-motparter b { font-variant-numeric: tabular-nums; }

/* Postlista. Inn og ut i hver sin kolonne, og ikke ett fortegnstall: et
   minustegn foran et beløp leses feil i en fart, og to kolonner lar øyet
   summere hver side for seg. */
.hb-poster td, .hb-poster th { vertical-align: top; }
.hb-poster tbody tr { cursor: pointer; }
.hb-poster tbody tr:hover { background: var(--surface-2); }
.hb-poster tbody tr:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.hb-dato { white-space: nowrap; color: var(--muted); font-variant-numeric: tabular-nums; }
.hb-inn { color: var(--ok); font-variant-numeric: tabular-nums; }
.hb-ut { font-variant-numeric: tabular-nums; }
.hb-poster tfoot td { border-top: 2px solid var(--border-strong); font-variant-numeric: tabular-nums; }

/* Introen: regelverket som en egen skjerm. */
.hb-intro { display: grid; gap: 18px; }
.hb-introrad { display: flex; gap: 14px; align-items: flex-start; }
.hb-introrad h3 { font-size: .96rem; margin-bottom: 3px; }
.hb-introrad p { font-size: .87rem; color: var(--muted); line-height: 1.55; }
.hb-regler { display: grid; gap: 16px; }
.hb-regel { display: flex; gap: 14px; align-items: flex-start; }
.hb-regelbelop {
  flex: none; min-width: 92px; text-align: right;
  font-size: 1.05rem; font-weight: 680; font-variant-numeric: tabular-nums;
  padding-top: 1px;
}
.hb-regel h4 { font-size: .92rem; margin-bottom: 3px; }
.hb-regel p { font-size: .86rem; color: var(--muted); line-height: 1.55; }
.hb-vilkar { margin: 0; padding-left: 20px; display: grid; gap: 10px; }
.hb-vilkar li { font-size: .88rem; line-height: 1.55; }
.hb-vilkar .hint { display: block; margin-top: 3px; }

.hb-vilkarkort summary { cursor: pointer; list-style: none; }
.hb-vilkarkort summary::-webkit-details-marker { display: none; }
.hb-vilkarkort summary h2 { display: inline; font-size: 1rem; }
.hb-vilkarkort summary::after { content: ' ▾'; color: var(--muted); }
.hb-vilkarkort[open] summary::after { content: ' ▴'; }

.hb-handlinger { display: flex; justify-content: flex-end; gap: 8px; flex-wrap: wrap; }
/* Boka si egen tittelrad, over tallene. Flex og ikke `.card-head`: raden
   står utenfor et kort, og knappene skal til høyre for tittelen og ikke
   under den. `.grow` krymper først, så knappene blir aldri klemt bort. */
.hb-hode {
  display: flex; align-items: flex-start; gap: 10px;
  flex-wrap: wrap; margin-bottom: 16px;
}
.hb-hode .grow { flex: 1 1 220px; min-width: 0; }
.hb-hode h2 { font-size: 1.1rem; }
.hb-hode .grow p { margin-top: 2px; font-size: .86rem; }
.hb-aar { margin-bottom: 12px; }

@media (max-width: 560px) {
  /* Beløpet over tittelen i stedet for ved siden av: 92 px fast kolonne
     pluss en overskrift får ikke plass på 390 px uten at overskriften
     brekker etter hvert ord. */
  .hb-regel { flex-direction: column; gap: 4px; }
  .hb-regelbelop { text-align: left; min-width: 0; }

  /* Postlista: fire kolonner på 390 px klippet «Ut» av skjermkanten — altså
     halvparten av tallene, på en side man åpner for å se tall. Tre grep,
     i den rekkefølgen de koster minst:
       1. årstallet ut av datoen (årsvelgeren står rett over og har svart),
       2. luften i cellene ned fra 12 til 5 px,
       3. beskrivelsen får brekke, tallene aldri.
     Vannrett rulling var alternativet, og det er verre: det *gjemmer*
     beløpet i stedet for å trange det, og man må oppdage at det går an å
     dra. Samme grunn som brukerlista ikke ruller vannrett. */
  table.tbl.hb-poster th, table.tbl.hb-poster td { padding: 10px 5px; font-size: .82rem; }
  table.tbl.hb-poster th:first-child, table.tbl.hb-poster td:first-child { padding-left: 0; }
  table.tbl.hb-poster th:last-child, table.tbl.hb-poster td:last-child { padding-right: 0; }
  .hb-poster .hb-aar2 { display: none; }
  .hb-poster .hb-inn, .hb-poster .hb-ut { white-space: nowrap; }
}

/* ============================ domeneshop ============================ */

/* Domenelista (renderDomeneshop). Raden er en knapp som folder ut, ikke en
   lenke: det som ligger under er detaljer om det samme domenet, og et sted
   man kommer tilbake fra er noe annet enn et sted man går til.

   Ikke en `table.tbl`, som fakturaene under: en tabellrad kan ikke romme et
   utfoldet panel uten en `colspan` som brekker på en telefon, og lista her
   *er* en liste med detaljer under hver rad. Fakturaene er fire tall i rekke
   og hører i en tabell. */
.ds-liste { display: flex; flex-direction: column; }
.ds-rad { border-bottom: 1px solid var(--border); }
.ds-rad:last-child { border-bottom: none; }
.ds-rad.apen { background: var(--surface-2); border-radius: var(--r-md); }

.ds-hode {
  display: grid; width: 100%; gap: 6px 14px; align-items: center;
  grid-template-columns: minmax(0, 1.4fr) auto auto 18px;
  padding: 12px 10px; border: 0; background: transparent; cursor: pointer;
  color: var(--text); text-align: left; font: inherit;
  border-radius: var(--r-md);
}
.ds-hode:hover { background: var(--surface-2); }
.ds-rad.apen .ds-hode:hover { background: transparent; }
.ds-navn { font-weight: 590; font-size: .94rem; overflow-wrap: anywhere; }
.ds-utlop { display: flex; align-items: baseline; gap: 8px; font-size: .84rem; }
.ds-dato { color: var(--muted); font-variant-numeric: tabular-nums; }
/* Grått som standard: et utløp om to år er ingen beskjed. Fargene kommer av
   `dsAlvor()`, og terskelen står i den funksjonen alene så merket og varselet
   over lista ikke kan bli uenige. */
.ds-rel { font-size: .8rem; color: var(--faint); white-space: nowrap; }
.ds-rel.warn { color: var(--warn); font-weight: 600; }
.ds-rel.bad { color: var(--danger); font-weight: 600; }
.ds-merker { display: flex; gap: 6px; flex-wrap: wrap; }
.ds-pil { color: var(--faint); display: grid; place-items: center; }

.ds-detalj { padding: 2px 10px 14px; }
.ds-detalj .kv { grid-template-columns: 150px 1fr; }
.ds-dns { margin-top: 14px; }
.ds-dns .hint { margin: 8px 0 0; }
/* Tabellen kan bli bredere enn en telefon — en TXT-verdi er ofte en hel
   SPF-linje. Rullingen hører til omslaget og ikke til tabellen: `display:
   block` på selve tabellen gjorde at den krympet til innholdet sitt og sto
   som en smal stripe midt i et bredt kort. */
.ds-dnsrull { margin-top: 4px; overflow-x: auto; }
.ds-dnstabell { min-width: 420px; }
.ds-verdi { overflow-wrap: anywhere; max-width: 420px; }

@media (max-width: 560px) {
  /* Fire kolonner på 390 px klipper merkene ut av skjermkanten, og de er
     halve poenget med raden: «fornyes ikke» er det man leter etter. Navnet og
     pila står på første linje, utløpet og merkene under — samme grep som
     postlista i hobbyregnskapet, og av samme grunn: vannrett rulling *gjemmer*
     det i stedet for å trange det. */
  .ds-hode {
    grid-template-columns: minmax(0, 1fr) 18px;
    padding: 12px 4px;
  }
  /* Navnet og pila på første linje, resten under. Uten de to eksplisitte
     plasseringene havnet pila i raden *etter* merkene, sentrert på egen
     linje — autoplassering fyller neste ledige celle, og de to radene over
     spenner hele bredden. */
  .ds-navn { grid-column: 1; grid-row: 1; }
  .ds-pil { grid-column: 2; grid-row: 1; }
  .ds-utlop, .ds-merker { grid-column: 1 / -1; }
  .ds-detalj { padding: 2px 4px 14px; }
  .ds-detalj .kv { grid-template-columns: 1fr; gap: 2px; }
  .ds-detalj .kv dt { margin-top: 8px; }
  .ds-verdi { max-width: none; }
}
