/* Risk/Control/Deviation dashboard hero/summary tiles, badges, compliance overview lists, related responsive breakpoints.
   Split out of theme.css (original lines 443-1048) — 2026-08-18,
   CSS @layer restructuring step 2 (Basecamp "Fra Fizzy-gjennomgang:
   CSS-arkitektur"). Numeric filename prefix controls load order (see
   app/helpers/application_helper.rb#theme_stylesheet_link_tag) —
   files are concatenated in this exact original order, so no cascade
   tie-break changes. */
@layer overrides {
.controls-page {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
}

.controls-hero,
.controls-annex,
.controls-detail {
    border: var(--card-border);
    border-radius: var(--card-radius);
    background: var(--card-bg);
}

.controls-hero {
    display: grid;
    grid-template-columns: minmax(0, 1.3fr) minmax(320px, 0.9fr);
    gap: var(--space-4);
    padding: var(--space-5);
}

.ui-eyebrow {
    margin: 0 0 0.25rem;
    color: var(--text-500, #666);
    font-size: var(--text-size-xs);
    font-weight: 700;
    letter-spacing: 0.14em;
    text-transform: uppercase;
}

.controls-lead {
    margin: 0.75rem 0 0;
    max-width: 60ch;
    color: var(--text-700, #444);
    font-size: var(--text-size-lg);
    line-height: 1.65;
}

/* The lead column used to hold only .controls-lead's single sentence,
   leaving most of .controls-hero's left side empty next to the taller
   multi-tile status grid on the right — the "Totalt" figure moved in here
   (see shared/_stats_hero.html.erb) to give it real content. */
.controls-hero__lead {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.controls-hero__total {
    display: flex;
    align-items: baseline;
    gap: var(--space-2);
}

.controls-summary {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.75rem;
}

.controls-summary__tile {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    padding: var(--space-4);
    border-radius: var(--card-radius);
    background: var(--card-bg-muted);
    border: var(--card-border);
}

/* Kept raw, not a --text-size-* token: a big stat number reads as a
   small headline, not body/UI text — well above --text-size-xl's 1.05rem
   ceiling, same reasoning as .controls-annex__count and
   .compliance-overview-summary__value below. */
.controls-summary__value {
    font-size: 1.8rem;
    font-weight: 700;
    line-height: 1;
}

.controls-summary__label {
    color: var(--text-600, #666);
    font-size: var(--text-size-base);
    line-height: 1.4;
}

.controls-collections {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

.controls-annex {
    padding: var(--space-4);
}

.controls-annex__header,
.controls-detail__header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 0.9rem;
}

.controls-annex__meta {
    text-align: right;
}

/* .controls-detail__header's own justify-content: space-between only
   right-aligns a lone child once there's a second one to space away
   from — tasks/show.html.erb's completion toggle is the only thing in
   its header row (no status badge equivalent for a plain task), so it
   needs an explicit flex-end instead (Torleiv, 2026-08-20, "Style denne
   siden at den er konsistent med stil på andre sider" — moving the
   toggle from its old floating placement into this shared header idiom). */
.controls-detail__header--end {
    justify-content: flex-end;
}

/* Torleiv, 17.09.2026 (#10313472039): «fullfør ✅ oppe til venstre». Den
   sto til høyre etter 20.08.2026, da den ble flyttet inn i denne
   header-raden fra en flytende plassering. Venstre er der man leser først,
   og på en oppgave er «er den ferdig?» det første spørsmålet — ikke et
   valg man leter etter i motsatt hjørne av det man nettopp leste. */
.controls-detail__header--start {
    justify-content: flex-start;
}

/* sand_ui's .ui-badge sets width: fit-content with no white-space rule —
   fit-content still clamps to whatever space the containing flex/grid row
   actually has, so a badge sitting next to a long title (e.g. "Ikke
   Godkjent" beside a long Risk title) gets squeezed narrower than its own
   text and wraps mid-pill instead of just staying single-line and letting
   the row take the width it needs.
   Global rule (Torleiv, 2026-08-10): badge text should always read as
   UPPERCASE, never mixed-case — one rule here covers every badge in the
   app (Risk/Deviation/Control status, Document Utkast/Godkjent, "Ikke
   Godkjent", etc.) regardless of how each i18n string happens to be
   capitalized, so a new badge added later is correct automatically
   without anyone remembering to uppercase its own translation string.
   letter-spacing is the usual pairing for uppercase UI text — tightly-set
   capitals read as cramped without it. */
.ui-badge {
    white-space: nowrap;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

/* Torleiv, 2026-08-13: "gjør alle tags litt mindre dominerende" — sand_ui's
   own badge.css sizes every badge the same regardless of context
   (--height-xs, --spaceing padding), which reads fine as a deliberate
   status indicator (Risk/Control approval etc.) but too loud sitting
   inline next to a module card's own title. A modest, app-wide reduction
   in height/padding/font-size — not a color change, so the badge stays
   just as legible/functional as a status signal, only visually quieter. */
.ui-badge {
    height: 1.125rem;
    padding-inline: 0.4rem;
    font-size: 0.625rem;
}

/* Torleiv, 2026-08-13: "Under arbeid føles litt heavy" / "sjekk at tagger
   er konsistente ... følger farger 'godkjent' i systemet". Root cause:
   sand_ui's own badge.css pairs every other color's light background with
   its dark text at the same brightness distance (red/green/blue all use
   -200 background + -800 text) — yellow alone breaks that pattern with
   -400 background + a --amber-950 text color that doesn't even exist as a
   variable in this palette (falls back to plain black). That's what read
   as "heavier": every other badge is a soft tint, yellow was a solid,
   saturated fill. Realigned to the same -200/-800 pairing everything else
   uses — same yellow hue, same weight as "Godkjent"/"Ikke godkjent"/etc.

   Torleiv, 2026-08-13: still reported as less readable than the other
   badges even after that fix — turned out the -200/-800 PATTERN was
   right but --amber-800 itself isn't actually dark: sand_ui's red/blue/
   green scales are generated from a shared HSL brightness formula where
   every -800 stop sits at 20-27% lightness, but amber is a separate,
   hand-picked Material-Design-style hex scale where -800 (#ff8f00) is a
   vivid orange at ~50% lightness — nowhere near as dark. Measured the
   actual WCAG contrast ratio against the amber-200 background (#ffe082):
   --amber-800 only reaches 1.77:1, badly failing the 4.5:1 minimum for
   body text, versus ~7-11:1 for the other three hues' own -800-on-200
   pairing. A literal dark warm brown (not a sand_ui token — none of
   amber's own named stops are dark enough) gets this to a real 9.3:1. */
.ui-badge[data-color="yellow"] {
    --badge-color: #4d3000;
    --badge-border: var(--amber-200);
    --badge-bg: var(--amber-200);
}

/* Kept raw — see .controls-summary__value above. */
.controls-annex__count {
    display: block;
    font-size: 1.5rem;
    font-weight: 700;
    line-height: 1;
}

.controls-annex__label {
    color: var(--text-600, #666);
    font-size: var(--text-size-base);
}

.controls-list {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.controls-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: var(--space-4);
    align-items: start;
    padding: var(--space-4);
    border-radius: var(--card-radius);
    background: var(--card-bg-muted);
    border: var(--card-border);
    color: inherit;
    text-decoration: none;
    transition: transform 0.15s ease;
}

.controls-row:hover {
    transform: translateY(-1px);
}

.controls-row__body {
    min-width: 0;
}

/* Handlingene i radens andre kolonne (#10411858577, 18.10.2026).
   .controls-row er alt et tokolonners rutenett, så kolonnen finnes —
   det som manglet var at innholdet i den skulle stå på linje framfor å
   stables. Brukes av testregisterets funn, der en rad har både «Opprett
   avvik» og «Rediger». */
.controls-row__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: var(--space-2);
}

.controls-row__title {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.45rem 0.7rem;
}

.controls-row__number {
    color: var(--signal-color);
    font-size: var(--text-size-xs);
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.controls-row__name {
    font-weight: 600;
    line-height: 1.4;
}

/* Only .controls-row--task's own title is a real <a> — every other
   .controls-row usage makes the WHOLE row the link instead, so
   color/underline reset is already covered by .controls-row's own
   `color: inherit; text-decoration: none;`. This one needs its own copy,
   plus a hover underline standing in for the row-lift hover feedback
   .controls-row--task turns off (a checkbox sits right next to it, so
   the whole row lifting on hover read as if the checkbox were about to
   move too). */
a.controls-row__name {
    color: inherit;
    text-decoration: none;
}

a.controls-row__name:hover {
    text-decoration: underline;
}

.controls-row__meta {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem 0.8rem;
    margin-top: 0.4rem;
    color: var(--text-600, #666);
    font-size: var(--text-size-base);
    line-height: 1.45;
}

/* FORHÅNDSVISNING, IKKE HELE MERKNADEN (16.10.2026).

   Merknaden rendres som ren tekst i raden (se controls/_list.html.erb
   for hvorfor den ikke kan være rik), men den ble fortsatt vist i sin
   helhet. Målt i favoas: median 270 tegn, lengste 2 295. Én slik rad
   dytter resten av lista ut av syne, og da er lista ikke lenger noe man
   skummer.

   To linjer: nok til å kjenne igjen hva merknaden handler om, og til å
   avgjøre om man skal åpne kontrollen. Hele teksten står på
   kontrollens egen side, som raden lenker til.

   -webkit-box er fortsatt den eneste formen line-clamp virker i på
   tvers av nettlesere; de to -webkit-egenskapene hører sammen med den
   og er ikke etterlatt prefiks. */
.controls-row__note {
    color: var(--text-500, #777);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.controls-row__status {
    padding-top: 0.1rem;
}

/* "Mine todoer" (tasks/index.html.erb) — a real checkbox instead of the
   plain link .controls-row is everywhere else, so this variant swaps the
   usual body/status two-column grid for checkbox/body instead (Torleiv,
   2026-08-10: the list was unstyled, no checkbox, no source context). Not
   a link itself (unlike every other .controls-row) since it now contains
   an interactive checkbox — the title inside .controls-row__body is its
   own <a> instead. */
/* Third column added (Torleiv, 2026-08-12) for the assignee avatar group —
   checkbox | body | avatars. auto keeps it only as wide as the avatars
   actually need, same as the checkbox column. */
.controls-row--task {
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: center;
    cursor: default;
}

.controls-row--task:hover {
    transform: none;
}

.controls-row__checkbox {
    display: flex;
}

/* justify-self: end (not just relying on the auto-width 3rd grid track)
   — explicit right pin, per Torleiv 2026-08-12: "flytende helt til høyre",
   in case the row grid's own default row height ever exceeds a single
   line and centers this shorter column instead of pinning it. */
.controls-row__assignees {
    display: flex;
    align-items: center;
    justify-self: end;
}

.controls-row__due--overdue {
    color: var(--danger-color);
    font-weight: 600;
}

/* signatures/_entries_list.html.erb's "Evidens" tab log — Torleiv,
   follow-up on #10262462298: the .controls-row card-per-entry treatment
   above reads fine for a handful of controls/risks, but got visibly
   heavy once an evidence log's entry count grew ("slik det vises
   nedenfor blir det for plasskrevende", with a screenshot). One line per
   entry instead — border-bottom, no per-row card background — same
   density as .auth-methods-list's own rows (08_auth_and_account_
   settings.css), kept as its own class rather than reusing that one
   since its grid columns (toggle-slot, status-dot) are specific to an
   auth-methods list and don't apply here. */
.evidence-log {
    display: flex;
    flex-direction: column;
}

.evidence-log__row {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-1) var(--space-4);
    padding: var(--space-2) 0;
    border-bottom: 1px solid color-mix(in srgb, var(--text-900) 6%, transparent);
    font-size: var(--text-size-base);
}

.evidence-log__entry:last-child .evidence-log__row {
    border-bottom: none;
}

/* Det frosne notatet (#10344196461). Sammenslått som standard: lista er
   over 300 rader lang, og en instruksjon med sjekkliste i hver av dem
   ville gjort den uleselig. Ligger utenfor radlenka, ikke inni — en <a>
   inni en <a> splitter raden i tre. */
.evidence-log__snapshot {
    padding: 0 0 var(--space-2);
    font-size: var(--text-size-sm);
}

.evidence-log__snapshot > summary {
    cursor: pointer;
    color: color-mix(in srgb, var(--text-900) 60%, transparent);
}

.evidence-log__snapshot[open] > summary {
    margin-bottom: var(--space-2);
}

.evidence-log__description {
    min-width: 0;
}

.evidence-log__meta {
    display: flex;
    flex-wrap: wrap;
    gap: 0 var(--space-3);
    color: color-mix(in srgb, var(--text-900) 60%, transparent);
    white-space: nowrap;
}

/* Typefilteret over loggen (Torleiv, 11.09.2026: «lag filter på typer
   (avkrysningsbokser)»). En flytende rad, ikke et rutenett som
   .system-settings__checkboxes: etikettene her er ett ord og varierer i
   lengde, og antallet bokser følger hvilke typer som faktisk finnes i
   loggen — et fast tokolonners rutenett ville gitt store hull. */
.evidence-log__types {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-4);
    padding-bottom: var(--space-3);
    margin-bottom: var(--space-1);
    border-bottom: 1px solid color-mix(in srgb, var(--text-900) 6%, transparent);
}

.evidence-log__type {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-size-sm);
    cursor: pointer;
}

/* Tellingen er en opplysning, ikke en etikett — dempet, så blikket leser
   typenavnene som en liste og tallene bare når det spør etter dem. */
.evidence-log__type-count {
    color: var(--text-500, #666);
    font-variant-numeric: tabular-nums;
}

/* Sits inside .controls-annex__section-header (space-between) alongside
   the optional "open as own page" icon-link — grows to fill the row so
   the icon stays pinned to the end. */
.evidence-log__search {
    flex: 1;
    margin: 0;
}

/* Basecamp #10271000481 (point 2 + 3), signatures/index.html.erb's own
   standalone search field — distinct from .evidence-log__search above,
   which is the compact ISMS-tab preview's plain input with no filter
   attached.

   Point 2: .ui-input (sand_ui/form.css) sets no background at all —
   plain transparent, showing whatever's behind it. On THIS page that's
   .page-frame's own background (--page-bg, which resolves to --ui-0 —
   literally #fff), so the input was rendering white-on-white: a thin
   bordered box with no fill contrast, reading as "blends into the page"
   exactly as reported rather than a distinct search field. A literal
   "white" background wouldn't fix this — the page is ALREADY white
   (confirmed: --card-bg, the app's other "surface" token, is also
   #fff) — so this reaches for --ui-50 instead, the same soft off-white
   already used elsewhere purely to separate a surface from the page
   behind it (e.g. .outer-background). Locally scoped to .evidence-
   search__input only, not a change to .ui-input itself — that class
   backs form fields everywhere in the app, and a global background
   change there would be a much bigger, riskier change than what was
   actually asked for here.

   Point 3: .evidence-search wraps the input and the new person-filter
   <select> as ONE visually attached control — no existing "search box
   with a built-in filter" pattern elsewhere in the app to reuse (grepped
   for one); closest precedent is sand_ui/form.css's own .ui-input-box
   ("+ .ui-input-box" divides adjacent boxes with a light border rather
   than each having its own separate border), applied here as one
   shared outer border/radius/background with a divider between the two
   children instead of each carrying its own. */
.evidence-search {
    display: flex;
    align-items: stretch;
    background: var(--ui-50);
    border: var(--card-border);
    border-radius: var(--card-radius);
    overflow: hidden;
}

/* 2026-09-04 follow-up: border:none on .evidence-search__filter (below)
   was never enough on its own — a bare <select> keeps its native OS
   chrome (WebKit/Blink both render their own rounded pill with an inset
   shadow and dropdown arrow) until -webkit-appearance is also reset,
   which nothing here did before. That native chrome is exactly what
   made the input and the select read as two separate floating boxes
   instead of one bar. Both wrappers below exist so an icon can sit
   ABOVE the input/select via absolute positioning without either
   wrapper itself carrying a border/background of its own — the visual
   border/background still lives on .evidence-search alone. */
.evidence-search__input-wrap {
    position: relative;
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: center;
}

.evidence-search__icon {
    position: absolute;
    left: var(--space-3);
    top: 50%;
    transform: translateY(-50%);
    color: color-mix(in srgb, var(--text-900) 45%, transparent);
    pointer-events: none;
}

.evidence-search__filter-wrap {
    position: relative;
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    border-left: var(--spaceing-xxs) solid var(--border-color-light);
}

.evidence-search__filter-icon {
    position: absolute;
    right: var(--space-3);
    top: 50%;
    transform: translateY(-50%);
    color: color-mix(in srgb, var(--text-900) 45%, transparent);
    pointer-events: none;
}

.controls-detail {
    padding: var(--space-5);
}

/* #10292832557 (Torleiv: "editor må henge i toppen i edit-mode av felter
   på leverandør"): sand_ui's .ui-box carries overflow: hidden for its own
   rounded corners (components/boxes.css), and overflow: hidden makes the
   box a scroll container — so the Lexxy toolbar's position: sticky (see
   05_buttons_and_rich_content_editor.css) sticks relative to the box,
   which never scrolls, instead of the viewport. Measured live: editing a
   long assessment, the toolbar's top went to -600px with the text. clip
   clips the corners exactly the same way but creates no scroll
   container, so sticky descendants work again. Scoped to these detail
   sections rather than every .ui-box: clip does not establish a block
   formatting context the way hidden does, and the other boxes were not
   audited for margin-collapsing that might rely on that. */
.controls-detail.ui-box {
    overflow: clip;
}

.controls-detail__grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-3);
}

/* .list-item (sand_ui) is a single-line flex ROW by design — fine for the
   simple one-line rows it was built for, but shared/_version_history.html.erb
   reuses it for a genuinely multi-line entry (date+author, then the change
   reason, then an approval badge), and the shared class's row layout was
   cramming all of that onto one line with no gap ("Torleiv ÅreskjoldImportert
   fra Basecamp..." reading as one run-on string). Stack this specific list's
   items back into a column instead of overriding the shared class itself. */
.controls-detail__versions .list-item {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-1);
    padding-top: var(--space-3);
    padding-bottom: var(--space-3);
}

/* Mobile (#10276047895, Torleiv screenshot): "Oppgaver" ("Modulvis"
   view) reuses the same .list-item as every other reference-entry list,
   but its own task_entry_references/_task_entry.html.erb row crams a
   drag handle, checkbox, title, linked-record label, due date, avatar
   group AND a chevron onto that one .list-item flex line — the title
   was left with barely 100px, wrapping into a tall, narrow column while
   the date text broke mid-word. Scoped to .tasks-index specifically
   (same "don't touch the shared class" reasoning as
   .controls-detail__versions .list-item above) — this partial is also
   reused by agenda_items/show.html.erb, untouched here.
   .task-entry-row__meta is display:contents by default (its own rule,
   in the task-entry partial's own stylesheet neighborhood below) so
   this only changes anything below the breakpoint. */
@media (max-width: 640px) {
    .tasks-index .list-item {
        flex-wrap: wrap;
    }

    .tasks-index .task-entry-row__meta {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        flex-basis: 100%;
        gap: var(--space-2);
        margin-top: var(--space-1);
    }
}

.task-entry-row__meta {
    display: contents;
}

/* Document's own compact mode (see _version_history.html.erb's compact
   local) — one row instead of the full list, since the document's own
   "Historikk" page already renders that same full list in full further
   down (see versions.html.erb). */
.controls-detail__versions-summary {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex-wrap: wrap;
    font-size: var(--text-size-base);
}

/* #10280438445 (Torleiv: "viktigst: slippe å åpne versjoner for å
   godkjenne siste") — the latest version's own status/Approve action,
   always visible above the collapsed "Se full historikk" list below it
   (shared/_version_history.html.erb) rather than the last row inside
   it. Same card treatment .version-timeline__diff-frame already uses
   elsewhere on this same partial, so "here's the current state" reads
   as its own distinct block rather than blending into the page. */
.version-timeline__latest {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex-wrap: wrap;
    padding: var(--space-3) var(--space-4);
    margin: var(--space-2) 0 var(--space-3);
    border: var(--card-border);
    border-radius: var(--card-radius);
    background: var(--card-bg-muted);
}

/* #10280438445 (Torleiv: "Oppfølging (og å legge til ny) mer separat" —
   suppliers/show.html.erb stacks its own follow-up-tasks section
   directly above shared/_version_history.html.erb, both using the exact
   same .controls-detail__versions wrapper class, which read as one
   continuous block rather than two distinct sections). A plain <hr>
   would default to the browser's own thick inset styling — this is
   deliberately just a thin, quiet rule instead, consistent with the
   rest of this app's understated section boundaries (e.g.
   .system-settings__divider). Generic enough to reuse anywhere else a
   page stacks two of these mt-spaced sections back to back. */
.section-divider {
    border: none;
    border-top: var(--card-border);
    margin: var(--space-5) 0 0;
}

/* Basecamp #10268839444 ("Diff-visning av versjoner"): the field/change
   table inside each version row's own "Se endringer" <details>
   (shared/_version_history.html.erb) — sits inside the exact same
   .version-timeline__diff-frame box documents/versions.html.erb's own
   content diff already uses (06_document_history_and_toc.css). Minimal on
   purpose — reuses .controls-detail__label's muted/uppercase treatment for
   the header row rather than a new style.
   #10268839444 follow-up (Torleiv: "bygg inn rik tekst-diff også" + "merke
   med rødt og grønt" — the table used to just be two plain before/after
   columns): each row's own "Endring" cell now renders a real DocumentDiff
   (see Versionable#changed_fields_for) — ins/del below reuse the EXACT
   same colors as .version-timeline__diff's own ins/del rules just below in
   06_document_history_and_toc.css, deliberately not a second palette for
   the same "added/removed" concept. */
/* BEGRUNNELSEN I VERSJONSDIFFEN (#10382542166, 07.10.2026).

   Torleiv, med skjermbilde: «tekst i diff mer formatert». Klassen ble
   brukt i shared/_version_change_details.html.erb og hadde INGEN CSS i
   det hele tatt — den sto i malen som et navn uten innhold.

   Følgen var to ting på én gang. En sammenslått versjon rendres som en
   <ol> med én <li> per begrunnelse, men uten styling arvet den resetens
   list-style: none, så nummerne forsvant og flere begrunnelser leste som
   én sammenhengende blokk. Og en enkelt begrunnelse sto som en vegg uten
   luft.

   white-space: pre-line er det som gjør mest for ren tekst: et linjeskift
   noen har skrevet i begrunnelsen blir faktisk et linjeskift. HTML
   kollapser dem ellers, så den som skrev tre avsnitt fikk ett. Torleiv
   valgte 07.10.2026 å formatere ren tekst bedre framfor å gjøre
   change_reason til rik tekst: rik tekst ville endret API-kontrakten,
   lagringen og alle fire flater, og en begrunnelse skal leses raskt. */
.controls-detail__version-reason {
    white-space: pre-line;
    line-height: 1.5;
}

/* Nummerert og med luft, så to begrunnelser leses som to SKRITT og ikke
   som en gjentakelse. Det var nettopp forvekslingen på skjermbildet:
   to redigeringer med samme begrunnelse så ut som den samme teksten
   skrevet to ganger. list-style og padding settes eksplisitt fordi
   reseten nullstiller begge. */
ol.controls-detail__version-reason {
    margin: 0;
    padding-left: var(--space-5);
    list-style: decimal;
}

ol.controls-detail__version-reason li {
    padding-left: var(--space-1);
}

ol.controls-detail__version-reason li + li {
    margin-top: var(--space-2);
}

.version-field-diff {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--text-size-sm);
}

.version-field-diff th,
.version-field-diff td {
    text-align: left;
    padding: var(--space-1) var(--space-2);
    vertical-align: top;
}

.version-field-diff thead th {
    color: var(--text-500, #666);
    font-size: var(--text-size-xs);
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.version-field-diff tbody th {
    font-weight: 600;
    white-space: nowrap;
}

.version-field-diff tbody tr + tr {
    border-top: 1px solid color-mix(in srgb, var(--text-900) 8%, transparent);
}

.version-field-diff__value {
    line-height: 1.5;
}

/* Basecamp #10285613879 punkt 2 ("vis detaljer, ikke bare innhold
   endret"): den presise årsaken når ordnivå-diffen ikke er verdt å vise
   — se Versionable#diff_summary_text for de fire tilfellene. Dempet, for
   den forklarer diffen i stedet for å VÆRE den. */
.version-field-diff__summary {
    margin: 0;
    line-height: 1.5;
    color: color-mix(in srgb, var(--text-900) 65%, transparent);
}

/* Før/etter ved helomskriving — det ene tilfellet der detaljen finnes,
   men rødt/grønt ord-for-ord blir en vegg (ingenting av det gamle
   overlevde). Etiketten står over verdien, ikke ved siden av, fordi
   verdiene her kan være hele avsnitt. */
.version-field-diff__before-after {
    margin: var(--space-2) 0 0;
    display: grid;
    gap: var(--space-1);
}

.version-field-diff__before-after dt {
    font-size: var(--text-size-sm);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: color-mix(in srgb, var(--text-900) 55%, transparent);
}

.version-field-diff__before-after dd {
    margin: 0 0 var(--space-2);
    line-height: 1.5;
}

.version-field-diff__before-after dd:last-child {
    margin-bottom: 0;
}

.version-field-diff ins {
    background: rgba(47, 158, 68, 0.15);
    color: var(--success-color);
    text-decoration: none;
}

.version-field-diff del {
    background: rgba(178, 47, 47, 0.12);
    color: var(--danger-color);
    text-decoration: line-through;
}

.compliance-overview-page {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
}

.compliance-overview-hero {
    display: grid;
    grid-template-columns: minmax(0, 1.3fr) minmax(320px, 0.9fr);
    gap: var(--space-4);
    padding: var(--space-5);
    border: var(--card-border);
    border-radius: var(--card-radius);
    background: var(--card-bg);
}

/* #10280472169: the risk matrix moved INTO this box (see
   suppliers/index.html.erb's own comment) — a wider right column than the
   default minmax(320px, 0.9fr), since .risk-matrix__grid has a fixed 460px
   width and would otherwise scroll horizontally inside its own column on a
   perfectly roomy desktop. A flat 500px, not minmax(500px, auto): `auto`
   sizes to max-content, and the matrix panel's own intro line is wide
   enough that it grabbed two thirds of the box and squeezed the lead text
   into a three-line column (measured live at 1280px). */
.compliance-overview-hero--with-matrix {
    grid-template-columns: minmax(0, 1fr) 500px;
    align-items: start;
}

.compliance-overview-hero__main {
    display: flex;
    flex-direction: column;
    /* 16.09.2026 (#10309415397): the matrix beside this column is about
       twice as tall as the text and the three tiles, which left the whole
       lower half of the card empty. Centred against the matrix instead of
       pinned to the top — there is nothing honest to fill the space with,
       so the fix is to stop pretending the column is that tall. */
    justify-content: center;
    gap: var(--space-4);
}

.compliance-overview-eyebrow {
    margin: 0 0 0.25rem;
    color: var(--text-500, #666);
    font-size: var(--text-size-xs);
    font-weight: 700;
    letter-spacing: 0.14em;
    text-transform: uppercase;
}

.compliance-overview-lead {
    margin: 0.75rem 0 0;
    max-width: 60ch;
    color: var(--text-700, #444);
    font-size: var(--text-size-lg);
    line-height: 1.65;
}

/* Same reasoning as .controls-hero__lead/__total — the lead column used to
   hold only the eyebrow/title/intro block, leaving most of it empty next
   to the taller status-tile grid on the right. */
.compliance-overview-hero__lead {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.compliance-overview-hero__total {
    display: flex;
    align-items: baseline;
    gap: var(--space-2);
}

/* auto-fit rather than a fixed two (16.09.2026, #10307272252): the
   supplier register needs three tiles now — Totalt, I orden, Krever
   oppfølging — while Etterlevelse and Aktiva render one and Tjenester
   two. Every page keeps its tiles on one row where they fit, and they
   wrap on a phone instead of being squeezed. */
.compliance-overview-summary {
    display: grid;
    /* Torleiv, 17.09.2026 (#10313038626, skjermbilde): «KREVER OPPFØLGING»
       stakk ut over flisen sin på begge sider og la seg oppå tallet over, så
       «0» ble klippet på midten. Merket er en pille med fast høyde og
       width: fit-content (sand_ui badge.css) — den krymper ikke, den spiller
       over.

       8rem ga 128 px. Merket måler rundt 148 px med versaler, sperring og
       sin egen padding, og flisen har 32 px padding i tillegg. 11rem er det
       laveste som rommer det lengste merket vi har. Naboflisene blir like
       brede, som de skal, siden de deler samme kolonnespor. */
    grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
    gap: 0.75rem;
}

/* Sikkerhetsnettet, ikke selve fiksen: en lengre oversettelse skal brekke
   til to linjer inne i pillen framfor å spille ut av flisen igjen. Derfor
   auto høyde med min-height, ikke den faste høyden — et statusord skal
   aldri klippes. Gjelder begge flistypene, som deler dette mønsteret. */
.compliance-overview-summary__tile .ui-badge,
.controls-summary__tile .ui-badge {
    max-width: 100%;
    height: auto;
    min-height: var(--height-xs);
    padding-block: 2px;
    text-align: center;
}

/* Flisene er knapper siden 23.09.2026 (#10332079690): tellerne filtrerer
   lista under. font: inherit og margin: 0 fordi en <button> ellers tar
   nettleserens egne — og da krympet tallet til 13 px.
   Rammen er alltid der, bare i ulik farge: byttet den ut ved valg, ville
   boksen endret størrelse og raden hoppet. */
.compliance-overview-summary__tile {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: var(--space-2);
    padding: var(--space-4);
    margin: 0;
    border-radius: var(--card-radius);
    background: var(--card-bg-muted);
    border: var(--card-border);
    font: inherit;
    color: inherit;
    cursor: pointer;
    transition: border-color 120ms ease, background-color 120ms ease;
}

.compliance-overview-summary__tile:hover {
    background: var(--card-bg);
}

.compliance-overview-summary__tile:focus-visible {
    outline: 2px solid var(--text-900);
    outline-offset: 2px;
}

/* Valgt flis: mørk ramme og full bakgrunn. Ikke farge alene — aria-pressed
   bærer det for skjermleseren, og formen (den kraftigere rammen) bærer det
   i gråtoner. */
.compliance-overview-summary__tile[aria-pressed="true"] {
    border-color: var(--text-900);
    background: var(--card-bg);
}

/* «Totalt» er tilbakeveien, ikke et valg — den skal ikke se trykket ut
   bare fordi ingenting er filtrert. */
.compliance-overview-summary__tile--total[aria-pressed="true"] {
    border-color: var(--card-border-color, inherit);
    background: var(--card-bg-muted);
}

/* Kept raw — see .controls-summary__value above. */
.compliance-overview-summary__value {
    font-size: 1.8rem;
    font-weight: 700;
    line-height: 1;
}

.compliance-overview-summary__label {
    color: var(--text-600, #666);
    font-size: var(--text-size-base);
    line-height: 1.4;
}

.compliance-overview-empty {
    color: var(--text-600, #666);
    padding: var(--space-5);
    text-align: center;
}

/* #10258599737 ("Skulle vi vurdert tabell-aktig, med kolonner, som en
   kan sortere og filtrere etter?" — "kjør på med begge", Torleiv
   2026-09-01): suppliers/index.html.erb's own new sortable/filterable
   table (sortable_table_controller.js) — the app's first real data
   table, so nothing here to match/reuse; built fresh from the same
   card/spacing tokens (--card-bg, --card-border, --card-radius,
   --space-*) every other box in this file already uses. Deliberately
   NOT named .compliance-overview-row/-list — those are shared with
   assets/services/compliance_check_types' own div-based row lists
   (grid display, a whole row as one <a>), which a <tr> can't safely
   reuse (display: grid on a table row breaks table layout). */
.compliance-overview-filters {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

/* 16.09.2026 (#10309415397): the filters and the table share the column
   above, so without a row of their own each filter stretched across the
   whole page — two dropdowns reading «Alle» at full width, stacked, with
   the checkbox alone on a third line. Wraps on a narrow screen instead of
   squeezing. */
.compliance-overview-filter-row {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--space-4);
}

.compliance-overview-filter {
    display: inline-flex;
    flex-direction: column;
    gap: var(--space-1);
}

.compliance-overview-filter select {
    min-width: 12rem;
}

.compliance-overview-filter--checkbox {
    flex-direction: row;
    align-items: center;
    gap: var(--space-2);
    /* Lines up with the two dropdown filters' own baseline instead of
       sitting a label-height higher — those each have a <label> above
       the control, this is a single row with no separate label. */
    padding-bottom: 0.35rem;
}

/* Scrolls on its own — never the page body — same rule every wide
   table/code block in this app follows, since 5 columns won't fit a
   phone width no matter how tight the padding gets. */
.compliance-overview-table-wrap {
    overflow-x: auto;
}

.compliance-overview-table {
    width: 100%;
    min-width: 640px;
    border-collapse: collapse;
    border: var(--card-border);
    border-radius: var(--card-radius);
    /* A table can't clip its own rounded corners the way a div can —
       the header row's own background would otherwise square them off
       visibly at the top two corners. */
    overflow: hidden;
    background: var(--card-bg);
}

.compliance-overview-table th,
.compliance-overview-table td {
    padding: var(--space-3) var(--space-4);
    text-align: left;
    vertical-align: top;
}

.compliance-overview-table thead th {
    background: var(--card-bg-muted);
    color: var(--text-600, #666);
    font-size: var(--text-size-xs);
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    border-bottom: var(--card-border);
}

.compliance-overview-table thead th[data-sort-key] {
    cursor: pointer;
    user-select: none;
    transition: color 0.15s ease;
}

/* 15.09.2026 (UX review): the sort trigger is a real button inside the
   header cell, so it is reachable by Tab and Enter — styled to look like
   the plain header text it replaces, with a focus ring of its own. */
.compliance-overview-table__sort {
    all: unset;
    cursor: pointer;
    font: inherit;
    letter-spacing: inherit;
    text-transform: inherit;
    color: inherit;
}

.compliance-overview-table__sort:focus-visible {
    outline: 2px solid color-mix(in srgb, var(--text-900) 35%, transparent);
    outline-offset: 2px;
    border-radius: 2px;
}

/* #10278596584 (dark mode): rgb(28, 25, 20) is Blekk, this app's own
   dark-mode page background — hover text nearly vanished against it. */
.compliance-overview-table thead th[data-sort-key]:hover {
    color: var(--text-900);
}

/* Same arrow both directions, just flipped — aria-sort itself (set by
   sortable_table_controller.js) is what a screen reader actually
   announces; this is only the sighted hint for which column/direction
   is active. content: "" on the un-sorted state keeps every header's
   own width stable rather than the row reflowing width by width as
   sort state changes. */
.compliance-overview-table thead th[data-sort-key]::after {
    content: "";
    display: inline-block;
    width: 0.6em;
    margin-left: 0.3em;
}

.compliance-overview-table thead th[aria-sort="ascending"]::after {
    content: "↑";
}

.compliance-overview-table thead th[aria-sort="descending"]::after {
    content: "↓";
}

.compliance-overview-table tbody tr {
    border-bottom: var(--card-border);
    /* Torleiv, 2026-09-01 ("endre slik at klikk på hele raden åpner
       lev.kort"): position: relative here is what makes
       .compliance-overview-table__name's own ::after below size itself
       to the whole row, not just the name cell — the "stretched link"
       pattern (a real <a>, just invisibly covering the row) rather than
       a JS click handler, so cmd-click/right-click/"open in new tab"
       all keep working exactly like a normal link. */
    position: relative;
    cursor: pointer;
}

.compliance-overview-table tbody tr:last-child {
    border-bottom: none;
}

.compliance-overview-table tbody tr:hover {
    background: color-mix(in srgb, var(--text-900) 3%, transparent);
}

/* .assessment-dot er fjernet 20.10.2026 (#10416502773). Prikken som
   satte fargen inline ble erstattet av .assessment-count under, der
   fargen ligger i tokens fordi den må løse seg ulikt i lys og mørk
   modus — kommentaren der sier det selv. Igjen sto en CSS-regel ingen
   markup brukte, og en kommentar som viste til hjelperen
   supplier_assessment_completeness_color som om den fortsatt levde.
   Hjelperen er fjernet i samme runde. */

/* #10317451086, Torleivs skisse: «ta gjerne med antall "ting" vi venter
   på». Tallet leses først, fargen sier hvem som har trekket, merket i
   hjørnet sier at noe venter.

   currentColor gjennomgående, så én fargeregel per tilstand under styrer
   tall, ramme, fyll og merke samtidig. Fargen ligger i tokens og ikke
   inline nettopp fordi den må løse seg ulikt i lys og mørk modus — det var
   også grunnen til at den gamle prikken ikke kunne være annet enn en
   prikk. */
.assessment-count {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    border: 1.5px solid currentColor;
    background: color-mix(in srgb, currentColor 16%, transparent);
    font-size: var(--text-size-sm);
    font-weight: 700;
    line-height: 1;
    vertical-align: middle;
    margin-right: var(--space-2);
}

.assessment-count__number {
    color: currentColor;
}

/* Merket sitter oppe til høyre og stikker litt utenfor, som i skissen.
   Mørk sirkel med lys tegning, så det leses mot både fyllet og raden. */
.assessment-count__badge {
    position: absolute;
    top: -5px;
    right: -6px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 15px;
    height: 15px;
    border-radius: 50%;
    background: color-mix(in srgb, currentColor 78%, var(--text-900));
    color: var(--card-bg);
    line-height: 0;
}

/* Torleiv, 18.09.2026: «når 0: grønn og ✔ inni». Var stille grått med et
   0-tall. Grønt med hake sier det samme raskere, og det er positivt der
   det andre bare var fraværende — man leser «ferdig», ikke «ingenting». */
.assessment-count--empty {
    color: var(--success-color);
}

.assessment-count__check {
    line-height: 0;
}

.assessment-count--waiting_approval,
.assessment-count--waiting_us {
    color: var(--warning-color);
}

/* Blå, ikke amber: dette er ikke noe vi kan gjøre noe med, og da skal det
   ikke se ut som et krav. */
.assessment-count--waiting_supplier {
    color: var(--blue-600);
}

.assessment-count--attention {
    color: var(--danger-color);
}

/* done med et tall over null finnes ikke — telleren er null når ingenting
   venter, og da gjelder --empty. Regelen står likevel, så en framtidig
   tilstand som gir done med noe utestående ikke blir usynlig. */
.assessment-count--done {
    color: var(--success-color);
}

/* #10258599737 follow-up ("Gul ball før navn: Vis tooltip med lenke til
   todoen som setter status", Torleiv 2026-09-01): only used when the
   dot's own popover has a real task link to show (suppliers/index.html.erb) —
   position: relative + a real z-index so this small interactive target
   wins hover/click over .compliance-overview-table__name::after's own
   stretched link below, which otherwise paints on top of it (later in
   source order, same effective stacking level). */
.assessment-dot-wrap {
    position: relative;
    z-index: 1;
    display: inline-block;
    cursor: pointer;
}

/* Torleiv, 18.09.2026 (#10317451086, skjermbilde): «tooltip må ligge over
   andre elementer». Popoveren har z-index 20, men den lå likevel UNDER
   tellerne i radene nedenfor.

   Grunnen er stacking-kontekster: z-index: 1 over gjør hver wrapper til en
   egen kontekst, og popoverens egen 20 løses da INNI den — ikke mot sida.
   Radene under kommer senere i DOM-en, har sin egen kontekst på samme nivå,
   og maler derfor over. Å skru popoverens tall opp hjelper ikke; det er
   wrapperen som må løftes.

   :hover og :focus-within er nøyaktig de to måtene popoveren åpnes på (se
   hover_popover_controller.js), så den løftes bare mens den faktisk vises —
   og den opprinnelige grunnen til z-index: 1, at prikken skal vinne over
   radens egen strukne lenke, står urørt. */
.assessment-dot-wrap:hover,
.assessment-dot-wrap:focus-within {
    z-index: 30;
}

.assessment-dot-wrap .assessment-dot {
    margin-right: var(--space-2);
}

/* Same position: fixed reasoning as .risk-matrix__cell-popover — see
   hover_popover_controller.js. */
.assessment-dot-popover {
    display: none;
    position: fixed;
    z-index: 20;
    min-width: 180px;
    max-width: 280px;
    padding: var(--space-2) var(--space-3);
    background: var(--card-bg);
    border: var(--card-border);
    border-radius: var(--radius-sm);
    box-shadow: 0 4px 16px rgba(28, 25, 20, 0.18);
}

.assessment-dot-popover p {
    margin: 0 0 var(--space-1);
    font-size: var(--text-size-xs);
    color: var(--text-600, #666);
}

.assessment-dot-popover ul {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

.assessment-dot-popover a {
    color: inherit;
    font-size: var(--text-size-xs);
    text-decoration: none;
}

.assessment-dot-popover a:hover {
    text-decoration: underline;
}

.compliance-overview-table__name {
    color: inherit;
    font-weight: 600;
    text-decoration: none;
}

/* The stretched link itself — see the tr's own comment above. inset: 0
   sizes it to the whole row (the nearest position: relative ancestor),
   not just this cell, so a click anywhere on the row (a badge, the
   status dot, empty space) opens the supplier. */
.compliance-overview-table__name::after {
    content: "";
    position: absolute;
    inset: 0;
}

.compliance-overview-table__name:hover {
    text-decoration: underline;
}

.compliance-overview-table__flags {
    display: flex;
    flex-wrap: wrap;
    gap: 0.3rem;
}

/* #10258599737 ("blå er for sterk"): tjenestenavn-taggene er
   kategorisering, ikke status — ren tekst i sin egen kolonne
   ("Brukes av"), samme dempede farge som andre sekundære meta-tekster
   i denne filen (f.eks. .compliance-overview-row__meta), IKKE lenger
   fargede badges som konkurrerer med varsel-/status-badgene i
   naborcellene. */
.compliance-overview-table__tags {
    color: var(--text-600, #666);
}

/* Basecamp #10281121953 (Torleiv: "Kjør!" på stablede rader) — under
   ~700px slutter dette å være en tabell og blir én blokk per leverandør.

   Hvorfor, målt på 375px før endringen: tabellen er 695px i et 349px
   vindu, altså 50% synlig, og 346px måtte skrolles sidelengs. Verre enn
   det: navnekolonnen er ikke sticky, så når du skrollet til høyre for å se
   DPA-status og varsler, lå leverandørnavnet 167px utenfor skjermen — du
   leste "Mangler dokumentasjon" for en rad du ikke kunne se identiteten
   til. Et skrollehint ville bare fortalt deg at det fantes mer av noe du
   ikke kunne tolke når du kom dit.

   Og kolonnebredden var omvendt av verdien: av 22 leverandører hadde 21
   varsler (bredeste kolonne, 197px, helt utenfor skjermen) og 0 hadde
   "Brukes av" (88px, tom for samtlige).

   Målt etterpå, 22 leverandører: tabellen var 1483px høy, stablet er
   1987px — 34% mer vertikal skrolling, mot at all horisontal skrolling og
   hele identitetstapet forsvinner. Vertikal skrolling er det en telefon
   er god på.

   Bruddpunktet er 760px og ikke 700px fordi det er der tabellen faktisk
   får plass: den har min-width 640px, og innholdsspalten er ca. 100px
   smalere enn vindusbredden (målt: 601px spalte i et 701px vindu). Under
   ~740px overflyter tabellen uansett hvor lite padding den får, så på 700
   ville nettbrett fortsatt skrollet sidelengs — 94px, målt. */
@media (max-width: 760px) {
    /* Ingen skrollboks igjen å skrolle i. */
    .compliance-overview-table-wrap {
        overflow-x: visible;
    }

    .compliance-overview-table {
        display: block;
        min-width: 0;
        border: none;
        background: none;
    }

    /* Kolonneoverskriftene beskriver kolonner som ikke finnes lenger. */
    .compliance-overview-table thead {
        display: none;
    }

    .compliance-overview-table tbody {
        display: flex;
        flex-direction: column;
        gap: var(--space-2);
    }

    /* Hver rad blir sitt eget kort. position: relative beholdes fra
       regelen over — det er den som gjør at .compliance-overview-table__name
       sin ::after fortsatt strekker seg over HELE blokka, så et trykk hvor
       som helst på kortet åpner leverandøren (Torleiv, 01.09.2026: "klikk
       på hele raden åpner lev.kort"). Det mønsteret overlever stablingen. */
    .compliance-overview-table__row {
        display: block;
        padding: var(--space-3);
        border: var(--card-border);
        border-radius: var(--card-radius);
        background: var(--card-bg);
    }

    .compliance-overview-table td {
        display: block;
        padding: 0;
        border: none;
    }

    /* Navnet er overskriften i kortet. */
    .compliance-overview-table td:first-child {
        margin-bottom: var(--space-1);
        font-size: var(--font-size-md);
    }

    /* Risiko, DPA-status og varsler er alle korte merkelapper. De flyter
       som ÉN gruppe som brytes når den må, ikke som tre stablede
       fullbreddes rader — det var forskjellen mellom 104px og 76px per
       kort, målt. Alle tre cellene blir inline, og varselcellens egen
       flex-container blir inline-flex, ellers ville den brutt linja selv
       om cellen er inline. */
    .compliance-overview-table td:nth-child(2),
    .compliance-overview-table td:nth-child(3),
    .compliance-overview-table td:nth-child(4) {
        display: inline;
    }

    .compliance-overview-table__flags {
        display: inline-flex;
        vertical-align: middle;
    }

    /* Trust-merket hører til samme gruppe korte merkelapper (#10344248834,
       06.10.2026), så det flyter med dem framfor å bryte en egen rad.

       KLASSE OG IKKE nth-child: regelen over teller celle 2, 3 og 4, og
       den tellingen flyttet seg da trust-kolonnen kom inn som nummer 5.
       Et nytt tall i den lista ville brukket igjen neste gang noen
       setter inn en kolonne. */
    /* td MÅ være med i selektoren. `.compliance-overview-table td` over
       setter display: block og har høyere spesifisitet (0,1,1) enn
       klassen alene (0,1,0) — regelen traff aldri, og merket brøt sin
       egen rad. Fanget av testen, ikke av øyet. */
    .compliance-overview-table td.compliance-overview-table__trust {
        display: inline;
    }

    /* Tom celle koster ingen linje — samme prinsipp som «Brukes av»
       under. Streken er riktig i tabellen, der kolonnen finnes uansett;
       i et stablet kort er den bare en linje som sier ingenting. */
    .compliance-overview-table td.compliance-overview-table__trust[data-empty="true"] {
        display: none;
    }

    /* ERKLÆRINGEN OM ANVENDELIGHET STABLER ANNERLEDES (16.10.2026).

       Reglene over er formet etter leverandørkolonnene: celle 2, 3 og 4
       er korte merker der, og flyter derfor som én gruppe. I SoA-en er
       celle 2 et helt tiltaksnavn og celle 4 en dokumentreferanse — sydd
       sammen på én linje blir «A.5.1 Retningslinjer for
       informasjonssikkerhet I bruk IS-POL-01», uten et eneste skille.

       Nummer og navn er overskrifta i kortet, og står sammen på én
       linje. Resten er egne linjer med sin egen merkelapp, hentet fra
       kolonneoverskrifta gjennom data-label — thead er skjult her, og
       uten den er «IS-POL-01» en streng uten betydning.

       .compliance-overview-table-wrap FORAN i selektoren, og det er ikke
       pynt: uten den blir spesifisiteten (0,2,1) på begge sider, og da
       avgjør rekkefølgen i fila. Én regel flyttet, og SoA-kortene ville
       falt tilbake til leverandørformen — stille. Wrapperen løfter til
       (0,3,1) og gjør utfallet uavhengig av hvor reglene står. */
    .compliance-overview-table-wrap .compliance-overview-table--soa td.soa-table__number,
    .compliance-overview-table-wrap .compliance-overview-table--soa td.soa-table__title {
        display: inline;
        font-size: var(--font-size-md);
        margin-bottom: 0;
    }

    .compliance-overview-table-wrap .compliance-overview-table--soa td.soa-table__number {
        font-weight: 600;
        margin-inline-end: var(--space-1);
    }

    .compliance-overview-table-wrap .compliance-overview-table--soa td.soa-table__felt {
        display: block;
        margin-top: var(--space-1);
        font-size: var(--text-size-sm);
    }

    .compliance-overview-table-wrap .compliance-overview-table--soa td.soa-table__felt::before {
        content: attr(data-label) ": ";
        color: var(--text-600, #666);
    }

    /* Begrunnelsen er tom for 87 av 93 rader. En merkelapp uten verdi er
       bare en linje som sier ingenting. */
    .compliance-overview-table-wrap .compliance-overview-table--soa td.soa-table__felt[data-empty="true"] {
        display: none;
    }

    /* "Brukes av" vises bare når den har innhold. Samme prinsipp som
       Finder-lista for leverandørfiler (#10281481456): ingen linje skal
       koste plass på ingenting. data-empty settes i
       suppliers/index.html.erb — CSS kan ikke se at teksten er "–". */
    .compliance-overview-table__tags[data-empty="true"] {
        display: none;
    }

    .compliance-overview-table__tags:not([data-empty="true"]) {
        margin-top: var(--space-2);
    }
}

/* #10258599737 follow-up (2026-09-01, "burde vi laget en matrise på
   sannsynlighet vs konsekvens?... ja, og gjerne med visuell løsning"):
   the sannsynlighet x konsekvens overview heatmap, above the filter bar
   — .ui-box itself carries no padding (see this file's own note above),
   so every dimension here is explicit. */
/* #10280472169: no longer its own .ui-box below the hero — it's a panel
   INSIDE the hero now, styled like the summary tiles beside it (same muted
   fill and border) rather than carrying a second full card border inside
   an already-bordered box. */
.risk-matrix {
    padding: var(--space-4);
    border-radius: var(--card-radius);
    border: var(--card-border);
    background: var(--card-bg-muted);
    /* Required now that this is a GRID item rather than a block-flow child
       of the page: a grid item's automatic minimum size is its min-content
       width, and the 460px grid inside won this argument — measured live at
       375px, the whole hero (lead text and both tiles included) got pushed
       to 494px and clipped off the right edge of a phone screen. min-width: 0
       lets the track shrink again so .risk-matrix__grid-wrap's own
       overflow-x: auto scrolls the matrix, the way it did when this was a
       standalone .ui-box. */
    min-width: 0;
}

.risk-matrix__intro {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-3);
    margin-bottom: var(--space-2);
}

.risk-matrix__title {
    font-weight: 600;
}

.risk-matrix__unassessed {
    color: var(--text-600, #666);
    font-size: var(--text-size-xs);
}

.risk-matrix__axis-hint {
    color: var(--text-600, #666);
    font-size: var(--text-size-xs);
}

.risk-matrix__axis-hint--x {
    text-align: right;
    margin-top: var(--space-1);
}

/* Scrolls on its own — same rule the table below it follows — rather
   than shrinking 5 cells illegibly narrow on a phone width. */
.risk-matrix__grid-wrap {
    overflow-x: auto;
}

/* #10280472169 (Torleiv screenshot: "for stor, mye skrolling"): each
   cell's own aspect-ratio: 1 (below) ties its HEIGHT to whatever width
   the columns land on — free-growing 1fr columns on a wide desktop meant
   150px+ per column, so 5 rows of square cells alone pushed the supplier
   table off-screen. A fixed width instead of the old
   min-width-and-grow-forever means the matrix is exactly as tall as it is
   at its own designed minimum, on every screen size; below that width the
   grid-wrap's overflow-x:auto still scrolls it, unchanged. */
/* Antall kolonner kommer fra partialen (13.10.2026). Det sto `repeat(5, …)`
   hardkodet så lenge den eneste matrisen var sannsynlighet x konsekvens,
   begge med fem trinn. Aktivamatrisen er 3 x 4 — kritikalitet x
   klassifisering — og med fem kolonner fløt cellene over i feil kolonne
   mens aksetekstene havnet midt i rutenettet.

   Inline fra partialen og ikke repeat(var(--n)): var() inne i repeat()
   er ikke pålitelig på tvers av nettlesere. Regelen her er reserven for
   den som ikke sender noe. */
.risk-matrix__grid {
    display: grid;
    /* Sporene og bredden kommer fra partialen som EGENSKAPER, ikke som
       innebygde grid-template-columns/width — en innebygd stil slår
       enhver regel her, også mobilregelen lenger nede. Reservene er
       femkolonners-matrisen, for den som ikke sender noe. */
    grid-template-columns: var(--matrise-spor, auto repeat(5, minmax(60px, 1fr)));
    gap: 3px;
    width: var(--matrise-bredde, 460px);
}

.risk-matrix__row-label,
.risk-matrix__col-label {
    display: flex;
    align-items: center;
    color: var(--text-600, #666);
    font-size: var(--text-size-xs);
    padding: 0 var(--space-1);
}

.risk-matrix__col-label {
    justify-content: center;
    text-align: center;
}

/* score-based background is set inline (risk_matrix_cell_color) — one
   continuous hue sweep across 25 distinct cells doesn't fit a fixed set
   of CSS classes the way the three-level badge palette elsewhere does. */
.risk-matrix__cell {
    display: flex;
    align-items: center;
    justify-content: center;
    aspect-ratio: 1;
    /* #10280472169: caps the row height so five rows plus labels stay
       around 350px total — the cells read as a grid at 75x56 without the
       full square height a ~75px column would otherwise force. */
    max-height: 56px;
    border-radius: var(--radius-sm);
    color: white;
    font-weight: 700;
    font-size: var(--text-size-base);
}

/* #10322900543: tomme celler er en ring i sin egen farge, ikke det samme
   fyllet dempet ned. Bakgrunnen må derfor være gjennomsiktig — ringen
   settes inline sammen med fargen, av samme grunn som fyllet er det. */
/* Ringen rundt en tom celle. Torleiv, 06.10.2026 (#10373656171): «gjør
   rammene på de uten innhold være svake, samme farge som bokstaver, men
   svakere».

   BOKSTAVENE er aksetekstene over og til venstre — .risk-matrix__row-label
   og __col-label, begge var(--text-600). Ringen leser SAMME variabel og
   svekker den, i stedet for å ha en egen farge: endrer temaet tekstfargen,
   følger ringen med av seg selv, og den kan aldri komme i utakt med
   bokstavene den skal matche.

   Det gjør også at det ikke lenger trengs én verdi per tema. Ringen var
   til 06.10.2026 båndfarget og måtte være én fast hex for begge temaer —
   og da er 3,86:1 den laveste kontrasten den KAN ha mot både #F4F0E8 og
   #1A1C1B, fordi minimum ligger der de to kontrastkurvene krysser
   hverandre. Det gjorde den umulig å dempe. En gjennomsiktig farge har
   ikke det problemet: den legger seg oppå det underlaget som er der.

   Ringen bærer ikke lenger hvilket bånd cellen ligger i. Det er med
   vilje — en TOM celle har ingen data, og båndet kan leses av raden og
   kolonnen. Fargen er forbeholdt cellene det står noe i. */
.risk-matrix__cell--empty {
    background-color: transparent;
    box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--text-600, #666) 30%, transparent);
}

/* FYLT CELLE UTEN FARGE (aktivamatrisen, 17.10.2026). Grunnregelen gir
   hvit tekst, fordi fargen ellers kommer inline. Uten farge sto tallet
   hvitt på lys bunn — en fylt celle var umulig å skille fra en tom, målt
   på skjermbilde av /asset-register. Fyllet leser samme tekstvariabel
   som ringen rundt de tomme, bare sterkere, så det følger temaet av seg
   selv; tallet får sidas egen tekstfarge. */
.risk-matrix__cell--noytral {
    background-color: color-mix(in srgb, var(--text-600, #666) 22%, transparent);
    color: var(--text-900);
}

/* Only occupied cells get tabindex/the popover controller (see the
   view's own comment) — [tabindex] scopes this to those, not the
   unoccupied, outlined cells next to them. */
.risk-matrix__cell[tabindex] {
    cursor: pointer;
}

/* #10278596584 (dark mode): rgb(28, 25, 20) is Blekk, this app's own
   dark-mode page background — a focus outline in that color would be
   invisible on a dark cell, defeating the point of a focus indicator. */
.risk-matrix__cell[tabindex]:focus-visible {
    outline: 2px solid var(--text-900);
    outline-offset: 2px;
}

.risk-matrix__cell-wrap {
    position: relative;
}

/* position: fixed — see risk_matrix_popover_controller.js for why (the
   grid-wrap's own overflow-x:auto forces overflow-y:auto too, which
   would otherwise clip an absolutely-positioned popover for the
   top/bottom rows). top/left are set by the controller on show(). */
.risk-matrix__cell-popover {
    display: none;
    position: fixed;
    z-index: 20;
    min-width: 160px;
    max-width: 260px;
    padding: var(--space-2) var(--space-3);
    background: var(--card-bg);
    border: var(--card-border);
    border-radius: var(--radius-sm);
    box-shadow: 0 4px 16px rgba(28, 25, 20, 0.18);
}

.risk-matrix__cell-popover ul {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

.risk-matrix__cell-popover a {
    color: inherit;
    font-size: var(--text-size-xs);
    text-decoration: none;
}

.risk-matrix__cell-popover a:hover {
    text-decoration: underline;
}

/* #10251404406 ("Lag forslag til innhold på dashbord", forslag 2):
   cross-module status-sammendrag øverst på Oversikt-fanen — se
   systems/_status_summary.html.erb's egen kommentar. margin-bottom
   here (not a wrapper div around the list partial rendered right after
   it) is the same "let the component own its own spacing" reasoning as
   this file's other blocks — this partial has exactly one caller. */
/* #10254936220 ("Oversikt ISMS", "Padding og avstand i og mellom
   rammene"): .ui-box itself carries no padding of its own (sand_ui's own
   convention — see .isms-status-summary-attention's identical fix
   below), so this card's ring/stats used to sit flush against its own
   border, relying entirely on .governance-tabs__panel's shared padding
   around ALL three Oversikt cards rather than having any breathing room
   of its own. Same var(--space-4) the panel itself uses. */
.isms-status-summary {
    display: flex;
    align-items: center;
    gap: var(--space-5);
    margin-bottom: var(--space-5);
    padding: var(--space-4);
    flex-wrap: wrap;
}

.isms-status-summary__ring {
    position: relative;
    flex-shrink: 0;
    width: 108px;
    height: 108px;
}

.isms-status-summary__ring svg {
    width: 100%;
    height: 100%;
    /* Draw the progress arc starting at 12 o'clock instead of stroke-
       dasharray's own 3-o'clock default — the direction a "how much is
       done" ring is expected to start from. */
    transform: rotate(-90deg);
}

.isms-status-summary__ring-track {
    fill: none;
    stroke: var(--ui-100);
    stroke-width: 10;
}

.isms-status-summary__ring-value {
    fill: none;
    stroke: var(--signal-color);
    stroke-width: 10;
    stroke-linecap: round;
    /* 2 * π * r(42), the circle's own circumference — the one constant
       stroke-dasharray/-offset both need, tied directly to the r="42" on
       the same element in the .erb rather than left as an unexplained
       magic number here. */
    stroke-dasharray: 263.9;
    stroke-dashoffset: calc(263.9 - (263.9 * var(--isms-status-summary-pct, 0) / 100));
    transition: stroke-dashoffset 0.4s ease;
}

.isms-status-summary__ring-label {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    line-height: 1.2;
}

.isms-status-summary__ring-percent {
    font-size: 1.5rem;
    font-weight: 700;
}

.isms-status-summary__ring-caption {
    color: var(--text-600, #666);
    font-size: 0.75rem;
}

.isms-status-summary__stats {
    display: flex;
    gap: var(--space-5);
    flex-wrap: wrap;
}

.isms-status-summary__stat {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-1);
}

.isms-status-summary__stat-value {
    font-size: 1.3rem;
    font-weight: 700;
}

.isms-status-summary__stat-label {
    color: var(--text-600, #666);
    font-size: var(--text-size-base);
}

/* 2026-08-31 follow-up — see systems/_status_summary.html.erb's own
   comment: a separate, compact "trenger oppmerksomhet" list below the
   3-number row above, rendered only when it actually has something in
   it (empty items never reach this markup at all, see the .select in
   the partial), so a healthy module doesn't grow this box at all.

   #10254936220 ("Padding og avstand i og mellom rammene"): same
   zero-padding-of-its-own gap as .isms-status-summary above — this is
   also a .ui-box, so without its own padding the heading/list sat flush
   against the card's border. __link's own negative margin (see below)
   already accounts for extending its hover/focus background back out to
   this padding's edge, so the two stay in sync — change one, check the
   other. */
.isms-status-summary-attention {
    margin-bottom: var(--space-5);
    padding: var(--space-4);
}

.isms-status-summary-attention__heading {
    font-weight: 700;
    margin: 0 0 var(--space-3);
}

.isms-status-summary-attention__list {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    margin: 0;
    padding: 0;
    list-style: none;
}

/* #10254936220 ("Oversikt ISMS", "Lenker til de tinga som vises"): the
   badge+label pair now lives inside a real <button> (see the partial's
   own comment — tabs#select, jumps to the tab that lists these items),
   so the flex/gap layout moved from __item onto __link, and __link also
   needs the plain-button reset (border/background/padding/font/cursor)
   __item never had to think about. */
.isms-status-summary-attention__link {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    width: 100%;
    padding: var(--space-1) var(--space-2);
    /* Matches .isms-status-summary-attention's own padding (var(--space-4))
       above, not this element's own smaller padding — the hover/focus
       background needs to reach all the way to the card's edge, not stop
       var(--space-4) short of it. */
    margin: 0 calc(var(--space-4) * -1);
    border: none;
    border-radius: var(--radius-sm);
    background: none;
    font: inherit;
    text-align: left;
    cursor: pointer;
    transition: background-color 0.15s ease;
}

.isms-status-summary-attention__link:hover {
    background: color-mix(in srgb, var(--text-900) 6%, transparent);
}

.isms-status-summary-attention__link:focus-visible {
    outline: none;
    box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--text-900) 35%, transparent);
}

.isms-status-summary-attention__label {
    color: var(--text-600, #666);
    font-size: var(--text-size-base);
}

.compliance-overview-list {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.compliance-overview-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: var(--space-4);
    align-items: start;
    padding: var(--space-4);
    border-radius: var(--card-radius);
    background: var(--card-bg-muted);
    border: var(--card-border);
    color: inherit;
    text-decoration: none;
    transition: transform 0.15s ease;
}

.compliance-overview-row:hover {
    transform: translateY(-1px);
}

/* Gruppert plikt (#10348... 28.09.2026, Torleiv: «Jeg er usikker på om
   mange "Årlig gjennomgang av leverandørvurdering" er rett bruk på
   oversikt-sida»). Raden er en <button> og ikke en <a>, fordi den åpner
   noe på sida framfor å gå et sted — og en button arver ikke <a>-ens
   tekstjustering eller bredde, så de to må settes her for at gruppa skal
   stå på linje med de vanlige radene rundt. */
.compliance-overview-row--group {
    width: 100%;
    text-align: start;
    font: inherit;
    cursor: pointer;
}

/* Barna trekkes inn når gruppa er foldet ut, så det leses som at de
   hører til raden over og ikke som nye, likestilte rader. */
.compliance-overview-group [data-view-edit-target="edit"] {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    margin-top: var(--space-2);
    padding-inline-start: var(--space-4);
}

.compliance-overview-row__body {
    min-width: 0;
}

.compliance-overview-row__title {
    font-weight: 600;
    line-height: 1.4;
}

.compliance-overview-row__meta {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem 0.8rem;
    margin-top: 0.4rem;
    color: var(--text-600, #666);
    font-size: var(--text-size-base);
    line-height: 1.45;
}

.compliance-overview-row__status {
    padding-top: 0.1rem;
}

.people-invite-action--muted {
    color: color-mix(in srgb, var(--text-900) 35%, transparent);
    cursor: default;
    pointer-events: none;
}

.people-invite-action--error {
    color: var(--danger-color);
}

/* Long-form fields (a URL, free-text notes) span the full grid width
   instead of squeezing into the same column as short ones (Sannsynlighet,
   Status) — a fixed 2-column grid wrapping a whole paragraph or URL into a
   half-width cell reads as broken, not just cramped. */
.controls-detail__item--wide {
    grid-column: 1 / -1;
}

.controls-detail__item {
    padding: var(--space-4);
    border-radius: var(--card-radius);
    background: var(--card-bg-muted);
    border: var(--card-border);
}

/* #10342589057, 25.09.2026: Risiko skal kjennes som leverandørregisteret
   — feltene der er hvite (Supplier's egen .ark-innpakning, --card-bg),
   ikke sandfargede og flytende sammen med sida. Overstyrer bare
   FARGEN, ikke hele .ark-boksen (som har egen padding/kant/skygge og
   ville doblet opp mot .ui-box, som .controls-detail alt sitter i her)
   — samme narrow-scope-mønster som .document-metadata sin egen
   tilsvarende overstyring av akkurat denne regelen
   (04_document_layout_and_sheet.css). */
.risk-detail .controls-detail__item {
    background: var(--card-bg);
}

/* #10343730303, 26.09.2026: tiltak skal kjennes som leverandør og risiko.
   Samme smale overstyring som .risk-detail over — bare FARGEN, ikke hele
   .ark-boksen, som ville doblet opp mot .ui-box som .controls-detail alt
   sitter i.

   Gjelder også de to låste feltene (sikkerhetstiltak, veiledning). At de
   ikke kan redigeres skal vises ved at de ikke kan klikkes, ikke ved at
   de ser fremmede ut — Torleiv, samme dag: «låst innhold, samme
   utseende». */
.control-detail .controls-detail__item {
    background: var(--card-bg);
}

/* #10346447897, 30.09.2026: avvik skal kjennes som leverandør, risiko og
   tiltak. Torleiv la de to sidene ved siden av hverandre og så det med en
   gang — feltene på avvikssida var sandfargede mens 1Password sine var
   hvite. Avvikssida var den eneste av de fire som aldri fikk denne
   overstyringen, og hadde ikke engang en egen klasse å henge den på.

   Bare FARGEN, som de to over — ikke hele .ark-boksen, som ville doblet
   opp mot .ui-box som .controls-detail alt sitter i. */
.deviation-detail .controls-detail__item {
    background: var(--card-bg);
}

/* #10387146252, 08.10.2026. Torleiv, med skjermbilde av aktivakortet:
   «endre layout (særlig hva som er grått og hvitt) slik at samsvarer med
   lev.registeret».

   FJERDE GANG SAMME BESTILLING — risiko 25.09, tiltak 26.09, avvik, og
   nå aktiva. Målt før: feltene hadde rgb(244, 240, 232), nøyaktig samme
   sandfarge som sida bak, inne i en hvit .ui-box. Leverandørsida har
   ingenting sandfarget i det hele tatt.

   Bare FARGEN, som de tre over — ikke hele .ark-boksen, som ville doblet
   opp mot .ui-box som .controls-detail alt sitter i.
 */
.asset-detail .controls-detail__item {
    background: var(--card-bg);
}

/* Og tjenestesida, 08.10.2026 — den siste av de seks. Torleiv sa ja da
   jeg meldte at den sto igjen etter aktivakortet. Samme grep som de
   fire over. */
.service-detail .controls-detail__item {
    background: var(--card-bg);
}

/* #10355265186, 30.09.2026: dokumenthistorikken lastes ved klikk, i en
   lat turbo-ramme. En <turbo-frame> har display: contents som standard —
   ingen egen boks — og IntersectionObserver ser bare elementer som
   GENERERER en boks. Uten denne regelen fyrte den late lastingen aldri:
   ramma sto med riktig src og «Henter historikken…» i all evighet, med
   en fullt synlig forelder. */
.version-history-frame {
    display: block;
}

/* To rutenett etter hverandre — det låste referanseinnholdet og skjemaet
   — skal lese som ett sett felt. Uten dette står standardteksten som en
   innledning med luft under, og sida deler seg i to i stedet for å være
   én liste med felt (skjermbildet Torleiv sendte viste nettopp det). */
.controls-detail__grid--tight + .controls-detail__grid {
    margin-top: var(--space-3);
}

.controls-detail__label {
    margin-bottom: 0.35rem;
    color: var(--text-500, #666);
    font-size: var(--text-size-xs);
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
}

.controls-detail__value {
    line-height: 1.55;
    overflow-wrap: anywhere;
}

/* Torleiv, 09.09.2026: "Linjeskift lagres og går tapt ved visning... i
   praksis betyr det at avsnitt, nummererte punkter og punktlister er
   umulige — teksten blir en vegg."

   white-space ligger BEVISST på en egen modifier og ikke på
   .controls-detail__value selv. Den klassen er delt, og 14 bruksområder i
   fem visninger (suppliers 6, deviations 3, people 3, requirements 1,
   documents 1) har verdien på EGEN linje med tabulator-innrykk inne i
   div-en. Med pre-wrap på fellesklassen ville de innrykkene blitt synlig
   whitespace overalt — en layoutregresjon på leverandør-, avviks-, krav-,
   person- og dokumentvisningene. Verifisert med grep før valget, ikke
   antatt.
   
   pre-wrap og ikke simple_format: HTML kollapser sekvenser av mellomrom,
   så et nestet punkt ("  - underpunkt") mister innrykket sitt med <br>.
   Med pre-wrap overlever det. Punktlister var det viktigste i
   rapporten, og nestede punkter er nettopp det man skriver når man
   dokumenterer underleverandører eller sertifiseringsomfang. */
.controls-detail__value--multiline {
    white-space: pre-wrap;
}

/* #10258599737 ("Leverandør-register", "Show må ha like mye luft og
   rammer som edit. Helt likt, bare at det er grå tekst som aktiveres
   til sort når endring"): same padding/border/border-radius as
   .ui-input (sand_ui/form.css) — the display and the real input it
   swaps for now occupy visually identical boxes, so activating a field
   doesn't shift anything around it. Muted/gray text (var(--text-600))
   is what marks it as "not an active input yet, just showing you the
   current value" — .click-to-edit--dirty below (click_to_edit_controller.js,
   set on blur once a value actually differs from what it was when the
   field was activated) is the "this will change on save" signal color
   swaps to. */
.click-to-edit__display {
    display: block;
    width: 100%;
    /* Torleiv, 2026-09-01 ("deaktiverte felter må ha samme form, padding
       og margins som aktive"): boksen her matchet sand_ui sin EGEN
       .ui-input (padding 0.5em, radius --spaceing-xs, basis-skriftstørrelse)
       — men appen overstyrer .ui-input i 09_profile_and_dialogs.css med
       0.7em 1em, --radius-lg og --text-size-lg. Displayet lignet altså på
       gem-ets input, ikke på det inputet brukeren faktisk ser ved siden
       av, så feltet krympet og flyttet seg i det man klikket. De tre
       verdiene under er de samme som den overstyringen; endres den, må
       denne endres i samme slengen. */
    padding: 0.7em 1em;
    border: var(--spaceing-xxs) solid var(--border-color);
    border-radius: var(--radius-lg);
    cursor: pointer;
    transition: background-color 0.15s ease;
    overflow-wrap: anywhere;
    text-align: left;
    background: none;
    font: inherit;
    /* Etter `font: inherit` — den kortformen nullstiller font-size, så
       rekkefølgen her er betydningsbærende. */
    font-size: var(--text-size-lg);
    /* --text-700, ikke --text-600 (Torleiv, 23.09.2026: «Feil farge på
       tekst», skjermbilde av begrunnelsen for risikoaksept på 1Password).

       Grå med vilje siden #10258599737 — «grå tekst som aktiveres til sort
       når endring» — og den intensjonen står. Men den var MÅLT for lys:
       #7D7F7B mot hvitt kort gir 4,04:1, og WCAG AA krever 4,5 for
       brødtekst. Feltet står på 16 px, som ikke er «stor tekst».

       For en kort verdi leses 4,04 som dempet. For seksten linjer rik
       tekst leses det som deaktivert — og innholdet der var to
       dokumenterte beslutninger.

       --text-700 gir 7,1:1 og er fortsatt tydelig grått mot --text-900,
       så skillet mellom lest og endret består. */
    color: var(--text-700, #54595A);
}

.click-to-edit__display:hover {
    background: color-mix(in srgb, var(--text-900) 6%, transparent);
}

/* Merkelapper i et display sto klistret inntil hverandre: displayet får
   dem som en rekke <span>-er uten skilletegn (se suppliers/show sitt
   tags-felt), mens den aktive tag-velgeren legger sine egne chips i en
   flex-rad med mellomrom. Samme avstand her som .tag-picker bruker
   (--space-2), så raden ser lik ut før og etter at feltet aktiveres. */
.click-to-edit__display .ui-badge + .ui-badge {
    margin-left: var(--space-2);
}

/* #10258599737 ("I edit: Mer felter som vil bli endret ved lagring
   (etter at en har gått ut av feltet. F.eks. svak bakgrunnsfarge som
   markerer ulagret endring"): click_to_edit_controller.js toggles
   .click-to-edit--dirty on the wrapper — but the wrapper itself has no
   visible box of its own (.ui-input's input/textarea/select fills it
   at width:100%, no padding on the wrapper around that), so a rule
   scoped to the wrapper's own background never actually painted
   anything visible. Targets the real controls directly instead.

   Torleiv, 15.09.2026 ("mellomlagres og markeres som endret (gul
   bakgrunnsfarge)"): a changed field now CLOSES on the way out and the
   display shows the staged value, so .click-to-edit__display is the
   rule that carries the tint in practice; the input/textarea/select
   rules cover the one kind that stays open (a radio group, the
   tag-picker) because its display can't be re-rendered client-side. */
.click-to-edit--dirty .click-to-edit__display,
.click-to-edit--dirty [data-click-to-edit-target="input"] input,
.click-to-edit--dirty [data-click-to-edit-target="input"] textarea,
.click-to-edit--dirty [data-click-to-edit-target="input"] select {
    /* #10278596584 (dark mode): the yellow "dirty" tint stays fixed
       across themes (a semantic status color, not a surface color) —
       only the text color needs to flip, same reason as the other
       rgb(28, 25, 20) fixes in this file. */
    background: rgba(234, 179, 8, 0.1);
    color: var(--text-900);
}

/* Kortet mellomlagret som helhet (#10306663483), med sin egen gule tone
   på verdiene. Fra 16.09.2026 (#10309477228) redigeres hvert felt for
   seg, og markeringen kommer fra .click-to-edit--dirty over — samme
   regel som leverandørkortene. Den egne regelen er borte fordi den ikke
   lenger kan treffe noe. */

/* Lagrebåndet (#10355287123, 30.09.2026).
   Torleiv, med skjermbilde av et avvik: «Lagre knapp i båndet som ikke
   skjules ved skroll. Gjelder alle typer dokumenter, oppføringer osv.»
   Avklart samme dag: ALLTID SYNLIG, og Lagre gråes ut til det finnes en
   endring. NEDERST, ikke øverst.

   Det snur to tidligere valg, og begge sto forklart:

   Blokka var skjult til skjemaet var endret (#10261612187) — en side man
   bare LESER skulle ikke se ut som et skjema. Nå står båndet alltid, og
   det er knappens egen tilstand som sier forskjellen. Utgråingen er
   derfor ikke pynt: den bærer hele opplysningen den skjulingen bar før.
   unsaved_changes_controller.js setter disabled, ikke bare en farge — en
   knapp som SER utilgjengelig ut og åpner dialogen likevel er verre enn
   en som ikke fantes.

   display: contents er borte. Blokka deltok med vilje ikke i layouten, så
   barna fløt inn i foreldrenes rutenett — og et bånd må være det
   motsatte: et ekte element med egen posisjon.

   position: fixed og ikke sticky: sticky holder bare så lenge
   FORELDREN er i bildet, og båndet bor inni skjemaet, som slutter
   midtveis på sida. Et sticky bånd ville forsvunnet nettopp når man
   skroller ned til versjonshistorikken — altså det motsatte av «skjules
   ikke ved skroll».

   NEDERST er også der tommelen er på mobil. */
/* Høyden står ETT sted, og den står på <body>: hjelpeknappen og
   sidefelt-knappen løftes over båndet med den (se .support-button i
   03_…), og de bor i en helt annen gren av dokumentet. En variabel satt
   på båndet selv ville bare arvet nedover til båndets egne barn — den
   ville vært usynlig for dem som faktisk trenger tallet, og de ville falt
   tilbake på reserven uten at noe sa fra. */
/* :not(.save-actions--tom) PÅ ALLE FIRE, og det er ikke pynt (16.10.2026).
   Etter at båndet begynte å forsvinne når det ikke har noe å tilby, sto
   det fortsatt i DOM-en — bare skjult. Og alle reglene her reagerte på
   at det FANTES, ikke på at det VISTES: hjelpeknappen svevde 68px over
   en tom bunn, innholdet fikk 5rem dødt rom under seg, og scroll-padding
   holdt av plass til ingenting. Testene som målte hjelpeknappen fant det.

   Én tilstand, lest likt overalt: synlig bånd, eller ikke. */
body:has(.save-actions:not(.save-actions--tom)) {
    --save-bar-height: 3.25rem;
}

/* Et fast bånd nederst gjør den nederste stripen av vinduet uNÅBAR, og
   det rammer mer enn øyet: nettleserens egen «rull dette fram»
   — et anker i adressen, tabulator til et felt, scrollIntoView — legger
   gjerne elementet nøyaktig der.
   MÅLT 02.10.2026: et flagg på leverandørsida havnet på y 1241–1257 i et
   vindu på 1257, og elementFromPoint svarte .save-actions. Tooltipen
   kunne ikke åpnes i det hele tatt.
   scroll-padding er nøyaktig det denne egenskapen finnes for, og den
   virker for et menneske og for en test på samme måte. Satt på begge
   mulige rullebokser: hvilken av dem som ruller avhenger av layouten. */
html:has(.save-actions:not(.save-actions--tom)),
body:has(.save-actions:not(.save-actions--tom)) {
    scroll-padding-bottom: calc(var(--save-bar-height, 3.25rem) + var(--space-4));
}

.save-actions {
    position: fixed;
    inset-inline: 0;
    bottom: 0;
    /* Under tooltipene (z-index 20), over innholdet. Et bånd som legger
       seg OVER en hjelpeboks ville skjult nettopp det man nettopp ba om
       å få se. */
    z-index: 15;
    display: flex;
    justify-content: flex-end;
    gap: var(--space-sm, 0.5rem);
    padding: var(--space-sm, 0.5rem) var(--space, 1rem);
    padding-bottom: max(var(--space-sm, 0.5rem), env(safe-area-inset-bottom));
    /* --card-bg og --border-color, ikke oppdiktede navn: båndet er et
       kort som ligger over innholdet, og de to tokenene er dem resten av
       appen bruker til nettopp det. De følger også mørk modus av seg
       selv. Første forsøk skrev --bg-100/--border-200, som ikke finnes
       noe sted — båndet fikk da reserven #fff og en nesten usynlig strek
       mot en kremfarget side. */
    background: var(--card-bg);
    border-top: 1px solid var(--border-color);
    box-shadow: 0 -2px 8px rgb(0 0 0 / 6%);
}

/* ET BÅND UTEN NOE Å TILBY FINNES IKKE (Torleivs valg 16.10.2026: «vi
   kan ikke vise lagre, godkjenn, avvis, publiser hele tiden»).

   Klassen settes av unsaved_changes_controller, som alt vet hvilke
   knapper den styrer og hvilke den lar være — godkjenning, utgivelse og
   lenker. Regelen kunne stått her i CSS med :has(), men da måtte den
   gjettet på de samme unntakene en gang til, med en egen liste som
   kunne skille lag med kontrollerens.

   display: none og ikke visibility: hidden — båndet er fixed, så det
   flytter ingenting når det forsvinner, og høyden skal bli 0 slik at
   --save-actions-height følger etter og sidefeltet får plassen tilbake.
   Se save_actions_height_controller.

   GOD PRAKSIS SIER Å BEHOLDE EN GRÅ LAGRE-KNAPP, og rådet er riktig for
   en knapp inne i et skjema: der er den en del av innholdet. Dette
   båndet er ramme, ikke innhold. Innvendingen — at man ikke skjønner at
   lagring finnes — dør av at båndet kommer i samme øyeblikk man skriver. */
.save-actions--tom {
    display: none;
}

/* OG LAGRE ALENE, når båndet står der for noe annet (Torleiv
   16.10.2026, skjermbilde av A.5.16: en grå Lagre ved siden av
   Godkjenn). Båndet SKAL stå der — det har en godkjenning å tilby — men
   lagreknappen hører ikke hjemme i det før noe er endret.

   Klassen settes av unsaved_changes_controller, som alt vet hvilke
   knapper den styrer og hvilke den lar være. Er lagreknappen den eneste
   i båndet, er det --tom-regelen over som tar hele båndet. */
.save-actions__skjult {
    display: none;
}

/* Lagre skal GRÅES UT til det finnes en endring (Torleiv, 30.09.2026).
   sand_ui hadde bare en regel for a.ui-button[disabled] — en ekte
   <button disabled> så helt upåvirket ut, altså full styrke og
   signalfarge på en knapp som ikke kan trykkes. Utgråingen bærer hele
   opplysningen den gamle skjulingen bar, så den kan ikke mangle. */
.save-actions .ui-button:disabled {
    opacity: 0.45;
    cursor: not-allowed;
}

/* Barnet bærer .controls-detail__item--wide fra den gamle formen, der det
   betydde «ta hele rutenettbredden». I et bånd betyr det ingenting, og
   uten dette ville det tatt all plassen og dyttet knappen ut til venstre
   på smale skjermer. */
.save-actions > * {
    width: auto;
    max-width: 100%;
}

/* Båndet ligger OVER sida, så det siste innholdet må få plass til å komme
   fram under det. :has() framfor en klasse på hver av de sju malene: det
   er sida som HAR et bånd, ikke sida som husket å si fra.

   .page-content og ikke <main>: appen har ikke noe <main>-element — bare
   den offentlige dokumentvisningen har det, og den har ikke noe bånd.
   Dette er feilen en :has()-regel skrevet etter hukommelse ville gjort,
   og den ville vært usynlig: regelen matcher ingenting, båndet dekker det
   siste innholdet, og ingenting sier fra. */
.page-content:has(.save-actions:not(.save-actions--tom)) {
    padding-bottom: 5rem;
}

@media print {
    .save-actions { display: none; }
    .page-content:has(.save-actions:not(.save-actions--tom)) { padding-bottom: 0; }
}

/* #10261612187 follow-up ("Endre slik at tekst i editor-felt er grå når
   ikke edit"): .ui-document-rich-content's own --lexxy-color-ink
   variable (sand_ui/components/document.css) sets full-strength ink
   color unconditionally — a plain `color` override on
   .click-to-edit__display alone never reached the Lexxy-rendered text
   inside it, since Lexxy paints its own content through that variable,
   not by inheriting the ancestor's `color`. */
.click-to-edit__display .ui-document-rich-content {
    --lexxy-color-ink: var(--text-600, #666);
    color: var(--text-600, #666);
}

/* :focus, not :focus-visible — see .governance-tabs__tab:focus's own
   comment (04_document_layout_and_sheet.css, #10254936220, 2026-09-01):
   Safari doesn't reliably match :focus-visible after a plain mouse
   click, so a rule gated behind it can silently never apply there,
   leaving the browser's own unstyled default outline in its place
   instead. Unconditional :focus applies the SAME ring in every browser
   regardless of that mismatch. */
.click-to-edit__display:focus {
    outline: none;
    box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--text-900) 35%, transparent);
}

/* #10258599737 ("mer luft, bedre plassering, mer diskre", Torleiv
   2026-09-01): "+ Legg til oppgave" (suppliers/show.html.erb) and
   "Versjonshistorikk" (shared/_version_history.html.erb) both toggle a
   view_edit_controller.js section open — plain .ui-link read as too
   loud/link-like for what's meant to be a quiet, secondary affordance,
   and the two sat right on top of each other with nothing marking them
   as belonging to two different blocks (Oppfølging vs. Versjonshistorikk).
   Same muted color treatment as .controls-annex__section-link's own
   discreet "open as own page" icon-link (04_document_layout_and_sheet.css)
   — not that class itself, since this one is a real <button>, not an
   icon-only link, and needs its own underline/no-underline + spacing
   rules. margin-top separates it from whatever's above it (the task
   list's own empty-state text, or the block before Versjonshistorikk),
   without needing a second .mt wrapper at each call site. */
/* KLIKKFLATE (#10371227376): 142,5 × 22,5. Dette er en knapp, ikke en
   lenke i en setning, så den må være minst 24 høy (WCAG 2.2, 2.5.8).
   inline-flex framfor inline-block, så min-height faktisk virker. */
.section-toggle-link {
    display: inline-flex;
    align-items: center;
    min-height: 24px;
    margin-top: var(--space-3);
    /* KONTRAST (#10371227376, 05.10.2026). 45 % ga 2,86:1 i lyst tema —
       under kravet på 4,5:1 for 15px. Målt: 60 % gir 4,51, altså så vidt
       over og innenfor avrundingen av grensen; 70 % gir 6,31 lyst og
       7,94 mørkt. Valgte 70 % fordi en kontrast som akkurat så vidt
       består, ryker ved neste justering av bakgrunnen. */
    color: color-mix(in srgb, var(--text-900) 70%, transparent);
    text-decoration: none;
    transition: color 0.15s ease;
}

/* #10278596584 (dark mode): rgb(28, 25, 20) is Blekk, this app's own
   dark-mode page background — hover text nearly vanished against it. */
.section-toggle-link:hover {
    color: var(--text-900);
    text-decoration: underline;
}

/* Wraps a .ui-file-meta card (sand_ui) in a plain link to open/download it
   (suppliers/show.html.erb's documentation evidence) — resets the
   anchor's own default blue/underline so the card's own styling reads
   through unchanged, matching a.controls-row__name's own reasoning for
   the same "the whole thing is a link" pattern. */
.controls-detail__file-link {
    display: block;
    color: inherit;
    text-decoration: none;
}

/* requirements/show.html.erb's "Oppfylles av" list — plain, not
   .controls-list's own card-row treatment, since these are just links
   out to other resources' own show pages, not this page's own rows. */
.controls-detail__list {
    margin: 0;
    padding: 0;
    list-style: none;
}

.controls-detail__list li + li {
    margin-top: var(--space-1);
}

.controls-detail__list-link {
    /* 15.09.2026: was var(--ink, #1c1914) — --ink is defined nowhere, so
       the fallback always won: near-black links on Blekk in dark mode. */
    color: var(--text-900);
}

.controls-reference__link {
    display: inline-flex;
    align-items: center;
    padding: 0.2rem 0.55rem;
    border-radius: var(--radius-pill);
    background: var(--signal-color-tint);
    color: var(--signal-color);
    font-weight: 600;
    text-decoration: none;
}

.controls-reference__link:hover {
    /* 15.09.2026: was a fixed light blue; with --signal-color Bein in dark
       mode that made near-white text on light blue. Same mix as the rest
       of the app's hover fills. */
    background: color-mix(in srgb, var(--signal-color) 22%, var(--card-bg));
    text-decoration: underline;
}

/* #10313366437: det gamle vurderingsfeltet, beholdt fordi det inneholder
   revisjonsspor som ikke står noe annet sted. Dempet og med en tynn strek
   til venstre — det skal leses som et sitat fra før, ikke som en vurdering
   som konkurrerer med den over. */
.legacy-assessment {
    border-left: 2px solid var(--ui-200);
    padding-left: var(--space-3);
}

.legacy-assessment__why {
    margin: 0 0 var(--space-2);
    font-size: var(--text-size-sm);
}

.legacy-assessment .controls-detail__value {
    color: var(--text-700);
}

/* #10313677083: eieren er en rolle, og under den står de som faktisk
   holder den.

   ÉN LINJE FRA 13.10.2026 (#10399092218). Torleiv, med skjermbilde:
   «Vis tittel og navn på samme linje.» Det snur avgjørelsen som sto her
   — «To linjer, ikke én» — og begrunnelsen den hvilte på var at rollen
   og personen ikke skal lese som ETT navn.

   Den bekymringen er løst i utførelsen framfor ved å bli stående:
   rollen beholder sin egen vekt, og gap-en mellom dem er større enn et
   ordmellomrom. «CEO» og «Leif» leses som to ting på én linje.

   flex-wrap: en rolle med fire innehavere skal brekke til neste linje
   framfor å presse kortet ut i bredden. */
.asset-owner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
}

.asset-owner__role {
    font-weight: 600;
}

.asset-owner__holders {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
}

/* Flere referanser på samme felt (17.09.2026, #10309490519): én per rad,
   ikke en løpende linje — hver referanse er sin egen pille, og på en rad
   ville de to klistret seg sammen til noe som ser ut som én. */
.controls-reference__list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-2);
}

.controls-reference__separator {
    display: inline-block;
    width: 0.45rem;
}

@media (max-width: 900px) {
    /* Torleiv, 2026-08-17 (mobile audit, screenshot): .compliance-overview-hero
       (Egne tjenester) is the exact same minmax(0, 1.3fr) minmax(320px, 0.9fr)
       grid as .controls-hero — that fixed 320px right column never shrinks,
       so on a phone the left column got squeezed to almost nothing and its
       text wrapped one word per line. Missing from this list looks like an
       oversight when it was added, not a deliberate difference. */
    .controls-hero,
    .controls-detail__grid,
    .compliance-overview-hero {
        grid-template-columns: 1fr;
    }

    .controls-summary {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

/* #10280472169: the hero's matrix column needs 500px of its own, so this
   one variant has to stack earlier than the 900px breakpoint above — at
   950px the two columns would leave the text column unreadably narrow. */
@media (max-width: 1024px) {
    .compliance-overview-hero--with-matrix {
        grid-template-columns: 1fr;
    }
}

@media (max-width: 640px) {
    .controls-row {
        grid-template-columns: 1fr;
    }

    /* #10291208497 (Torleiv: "vis hele risikomatrisen på mobil også"): the
       fixed 460px above is the desktop answer to #10280472169 (too tall),
       but on a phone it left the two rightmost columns behind a horizontal
       scroll inside .risk-matrix__grid-wrap — the matrix exists to show
       where suppliers cluster, and the high-consequence end is exactly
       the part that was hidden. Full width with equal shrinkable columns
       (minmax(0, 1fr), not the 60px floor) fits all five on a 375px
       screen: the row-label column takes its own width ("Svært høy" at
       xs size), and each cell lands around 40px — still square via the
       cells' own aspect-ratio, and one digit reads fine at that size.
       Both label sets wrap at their own spaces ("Svært / høy") instead
       of forcing the tracks wider: the row-label column is capped so its
       two-word labels wrap and hand the width to the cells, and the
       column labels step down one size so "Middels" — the one label
       with no space to wrap at — fits a cell's width in one piece
       (overflow-wrap: anywhere would have split it "Midde / ls",
       measured live at 375px). */
    .risk-matrix__grid {
        width: 100%;
        /* --matrise-spor-smal er partialens eget sett uten 60px-gulvet,
           med riktig antall kolonner for aksen. Reserven er fem. */
        grid-template-columns: var(--matrise-spor-smal, auto repeat(5, minmax(0, 1fr)));
    }

    .risk-matrix__row-label {
        max-width: 3.4rem;
        line-height: 1.2;
    }

    .risk-matrix__col-label {
        padding: 0;
        font-size: 0.68rem;
        line-height: 1.2;
        /* break-word og IKKE anywhere (16.10.2026). Kommentaren over
           forkastet `anywhere` med rette: den brekker ivrig, og delte
           «Middels» som «Midde / ls» ved 375 px. `break-word` brekker
           bare et ord som ikke kan få plass på noen annen måte.

           Aktivamatrisens etiketter er klassifiseringer —
           «Konfidensiell» har ingen mellomrom å brekke på og måler 60 px
           i en celle på 52. Målt før: rutenettet sto riktig på 273 px,
           men to etiketter dyttet scrollWidth til 281. */
    }

    /* FRITEKST-ETIKETTER BREKKES, KJENTE TRINN GJØR DET IKKE
       (16.10.2026). Aktivamatrisens kolonner er klassifiseringer, og
       «Konfidensiell» er ett ord uten mellomrom å brekke på: målt 60 px
       i en celle på 52, som ga 8 px vannrett rulling ved 375 px.

       `anywhere` og ikke `break-word`: break-word viste seg å være for
       forsiktig her (målt — 281 px både før og etter), og min-width: 0
       trengs fordi etiketten er display: flex og teksten blir et anonymt
       flex-element som ellers ikke krymper under min-content.

       BARE på --fritekst. Risikomatrisen slår opp i risks.scale og har
       korte, kjente trinn; der delte `anywhere` «Middels» som
       «Midde / ls». Det er grunnen til at regelen er merket og ikke
       felles. */
    .risk-matrix__grid--fritekst .risk-matrix__col-label {
        overflow-wrap: anywhere;
        min-width: 0;
    }

    .controls-annex__header,
    .controls-detail__header {
        flex-direction: column;
    }

    /* #10276047895, found live on a supplier's own show page: the
       DPA/risk/tags badge row (suppliers/show.html.erb, a plain
       .flex.gap.items-center — same shape on Control/Risk/Deviation's
       own detail headers) never wrapped, so a supplier with several
       tags ran its badges past the right edge of a phone screen with
       no way to see the rest — not scrollable, genuinely cut off. */
    .controls-detail__header .flex {
        flex-wrap: wrap;
    }

    .controls-annex__meta {
        text-align: left;
    }

    .controls-summary {
        grid-template-columns: 1fr;
    }

    /* Same bare-flex-row-with-no-wrap bug as .controls-detail__header
       .flex above, on notices/edit.html.erb's own header actions
       (status badge + Send button + "..." dropdown) — all three ran
       off the right edge of a phone screen with no way to reach them. */
    .notice-edit__actions {
        flex-wrap: wrap;
    }
}

/* #10261930703 (Torleiv, risk_accepted checkbox — "behold synlig, gjør
   tydelig at den er irrelevant" i stedet for å skjule den): dims the box,
   not the checkbox's own functionality — see suppliers/_form.html.erb's
   own comment for why it's never HTML `disabled`. */
.is-irrelevant {
    opacity: 0.55;
}

.is-irrelevant p {
    color: var(--text-500);
}

/* Basecamp #10273302219 ("Registeret mangler en «avsluttet»-tilstand"):
   collapsed by default, muted — documentation to check when needed, not
   something competing for attention with the flagged register above it. */
.compliance-overview-terminated {
    margin-top: var(--space-4);
    color: var(--text-600);
}

.compliance-overview-terminated summary {
    cursor: pointer;
    font-weight: 600;
}

.compliance-overview-terminated__list {
    margin-top: var(--space-2);
    padding-left: var(--space-4);
}

.compliance-overview-terminated__date {
    color: var(--text-500);
    margin-left: var(--space-2);
}

} /* @layer overrides */

/* Basecamp #10271000481, second follow-up (Torleiv screenshot, 2026-09-04:
   the input/select still read as two separate boxes despite the
   border/appearance fixes above). Root cause traced live via the
   CSSOM (document.styleSheets), not guessed: 09_profile_and_dialogs.css's
   own ".ui-input, .ui-form input[type=...]..." rule ("App-wide: bigger,
   rounder, softer form fields") is DELIBERATELY unlayered — its own
   comment says so explicitly, "so plain selectors here win regardless
   of specificity" — which means it beats ANY layered rule, including
   @layer overrides, no matter how specific that layered rule is. A
   layered .evidence-search__input rule (previously here, inside
   @layer overrides above) could set padding-left to whatever it wanted
   and still silently lose to that unlayered rule's own
   `padding: 0.7em 1em` shorthand, since unlayered always beats layered
   for normal-priority declarations — the exact same fight already
   documented for .person-mention (application.css) and lexxy-toolbar
   (05_buttons_and_rich_content_editor.css), just one class collision
   deeper this time (via the shared .ui-input class, not a direct
   selector clash). Matching that same rule here — unlayered, and with
   .evidence-search prefixed in so this beats 09_'s bare `.ui-input`
   even on EQUAL unlayered footing (specificity (0,2,0) vs (0,1,0),
   not relying on source order alone, which this file's own position
   before 09_ in the manifest would otherwise lose). */
/* Mobile (#10276047895, found live while sweeping the app): .ui-input
   (sand_ui/form.css) never sets its own width, so the bare <input>
   fell back to the browser's intrinsic default (~229px) instead of
   filling .evidence-search__input-wrap's own flex:1;min-width:0 — a
   flex item's default min-width is auto, not 0, so the WRAPPER
   shrinking correctly on a narrow viewport didn't stop the INPUT
   itself from staying its full intrinsic width and overflowing into
   .evidence-search__filter-wrap right next to it (the two placeholders
   visibly overlapped, reading as garbled text). width: 100% here,
   same unlayered rule so it isn't lost to 09_'s own unlayered .ui-input
   (see this rule's own header comment above). */
.evidence-search .evidence-search__input {
    border: none;
    border-radius: 0;
    background: transparent;
    padding-left: 36px;
    width: 100%;
    min-width: 0;
}

.evidence-search .evidence-search__filter {
    border: none;
    border-radius: 0;
    background: transparent;
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
    padding-left: 12px;
    padding-right: 32px;
}

/* Torleiv, 16.09.2026 (#10309415397, oppfølging på leverandørsida): «mer
   konsistent avstand vertiklat nedover (luft er bra!)», «blir mye rammer i
   rammer nedover», «mer padding».

   Avstanden lå spredt som mt-md på noen barn og ingenting på andre, så
   rytmen nedover sprakk: målt på sida sto noen felt med 0 px mellom seg,
   andre med 16, 60, 95 og 120. Den settes ett sted nå, som gap på selve
   formen, og hvert barn arver den. Det er også grunnen til at mt-md er
   fjernet fra barna i show.html.erb — to kilder til samme avstand er
   nøyaktig det som lot dem sprike.

   Mer luft enn de 16 px som var vanligst: feltene her er bokser med egen
   ramme, og bokser tett i tett leser som én blokk i stedet for som en
   liste man kan skumme. */
.supplier-form {
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
    padding: var(--space-10);
}

/* Gruppen som mistet ramma si beholder rytmen sin — den er nå bare et
   avsnitt i den samme kolonnen, ikke en boks i en boks. */
.supplier-form__group {
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
}

/* Smalere skjerm: den ekstra luften koster mer enn den gir når bredden
   er knapp. */
@media (max-width: 768px) {
    .supplier-form {
        gap: var(--space-4);
        padding: var(--space-5);
    }

    .supplier-form__group {
        gap: var(--space-4);
    }
}

/* Sjekklista for leverandørdokumentasjon (#10331264204, 23.09.2026).
   Erstatter fritekstfeltet «Mottatt dokumentasjon». Radhøyden og luften
   følger personlista, som er mønsteret for «en rad per ting, med en
   handling til høyre». */
.doc-check__summary {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin: var(--space-3) 0;
}

.doc-check__row {
    display: flex;
    align-items: flex-start;
    gap: var(--space-4);
    padding: var(--space-4);
    border-bottom: 1px solid color-mix(in srgb, var(--text-900) 6%, transparent);
}

#supplier_documentation_items turbo-frame:last-child .doc-check__row {
    border-bottom: none;
}

.doc-check__main {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

.doc-check__label {
    font-weight: 600;
}

.doc-check__meta {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-2);
    font-size: var(--text-size-xs);
    color: color-mix(in srgb, var(--text-900) 65%, transparent);
}

.doc-check__file {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
}

.doc-check__note {
    margin: 0;
    font-size: var(--text-size-sm);
    color: color-mix(in srgb, var(--text-900) 80%, transparent);
}

.doc-check__actions {
    flex: 0 0 auto;
}

/* Stille utløser: «Endre» er ikke sidens hovedhandling, og sju knapper
   under hverandre ville dratt blikket bort fra selve lista. */
.doc-check__trigger {
    font-size: var(--text-size-xs);
    color: color-mix(in srgb, var(--text-900) 65%, transparent);
    cursor: pointer;
    text-decoration: underline;
    text-underline-offset: 2px;
}

.doc-check__trigger:hover,
.doc-check__trigger:focus-visible {
    color: var(--text-900);
}

/* Fire felt som hører sammen, på én linje der det er plass og under
   hverandre der det ikke er. Lagre-knappen står sist i skjemaet, «Fjern»
   utenfor det — en <form> inni en <form> kastes stille av nettleseren. */
.doc-check__form {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
}

.doc-check__form .ui-input {
    width: auto;
    min-width: 8rem;
}

.doc-check__add {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-top: var(--space-3);
}

.doc-check__add .ui-input {
    flex: 1 1 16rem;
}

@media (max-width: 640px) {
    .doc-check__row {
        flex-wrap: wrap;
    }

    .doc-check__actions {
        flex-basis: 100%;
    }
}

/* Hint under etiketten på et click-to-edit-felt (23.09.2026). Står i både
   lese- og redigeringsvisning: et hint som bare dukker opp når feltet er
   åpent hjelper ikke den som leser og lurer — og at det står i begge
   tilstander er også det som gjør at siden ikke hopper når feltet åpnes. */
.click-to-edit__hint {
    margin: var(--space-1) 0 0;
    font-size: var(--text-size-xs);
    line-height: 1.4;
    color: color-mix(in srgb, var(--text-900) 65%, transparent);
}

/* Torleiv, 22.09.2026, med skjermbilde av leverandørlista: «litt bredere
   navn-kolonne (unngå linjedeling)». «Anthropic (Claude og Claude Code)»
   brakk over to linjer, og raden ble dobbelt så høy som naboene — lista
   blir urolig å lese når øyet mister den loddrette linja gjennom merkene.

   width: 100% på FØRSTE kolonne er tabellens egen måte å si «denne tar
   resten»: de andre kolonnene krymper til innholdet sitt, og navnet får
   plassen som blir til overs. Ikke en fast bredde — det finnes alltid et
   navn som er lengre enn tallet man gjettet på.

   Skjermbildet viste mye tomrom etter «Intern», og det var nettopp
   symptomet: kolonnene delte plassen likt framfor etter behov. */
.compliance-overview-table th:first-child,
.compliance-overview-table td:first-child {
    width: 100%;
}

/* Og merkene skal ikke brekke innvendig. «RISIKOAKSEPTERT» delt over to
   linjer krever ikke mindre bredde — det ser bare ødelagt ut, og cella
   ber om like mye plass likevel. */
.compliance-overview-table td .ui-badge {
    white-space: nowrap;
}

/* «Mottatt» uten noe å vise til (#10331646015). FORMEN bærer forskjellen,
   ikke fargen: merket er fortsatt grønt, for det ER mottatt. Ikonet og
   teksten sier at det ikke finnes et dokument bak.

   Dempet, ikke rød: dette er ikke en feil. Noe dokumentasjon finnes bare
   som en e-post eller en side hos leverandøren, og da er notatet svaret.
   Men forskjellen skal kunne ses — et ubelagt ja leses som et belagt ett. */
.doc-check__unevidenced {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    color: var(--warning-color, color-mix(in srgb, var(--text-900) 60%, transparent));
}

.doc-check__summary--unevidenced {
    color: var(--warning-color, color-mix(in srgb, var(--text-900) 65%, transparent));
    font-size: var(--text-size-sm);
}

/* Torleiv, 23.09.2026, skjermbilde av 1Password: raden brøt sammen når
   redigeringsskjemaet var åpent. Navnet, merket og notatet ble presset til
   ett ord per linje mens de fire kontrollene tok all bredden.

   Årsaken: .doc-check__actions er flex: 0 0 auto, så skjemaet krever sin
   fulle bredde og hovedkolonnen får resten — som ble omtrent ingenting.

   Skjemaet får derfor hele linja for seg selv når det er åpent. :has() på
   [hidden]-tilstanden, ikke en klasse fra Stimulus: click_to_edit er delt
   av hele appen, og en radspesifikk tilstand hører ikke hjemme i den. */
.doc-check__row:has(.doc-check__actions [data-click-to-edit-target="input"]:not([hidden])) {
    flex-wrap: wrap;
}

.doc-check__row:has(.doc-check__actions [data-click-to-edit-target="input"]:not([hidden])) .doc-check__actions {
    flex-basis: 100%;
}

.doc-check__row:has(.doc-check__actions [data-click-to-edit-target="input"]:not([hidden])) .doc-check__form {
    justify-content: flex-start;
}

/* Fila er en lenke nå, ikke bare et navn — den skal se ut som en. */
a.doc-check__file {
    color: inherit;
    text-decoration: none;
}

a.doc-check__file:hover,
a.doc-check__file:focus-visible {
    text-decoration: underline;
    color: var(--text-900);
}

/* Hintet bak et spørsmålstegn ved etiketten (Torleiv, 23.09.2026: «flytt
   hjelpetekster inn i hover-tool-tip bak overskrifta»).

   Det sto først over feltet og dyttet boksen ned; så under feltet, som
   løste høydeforskjellen men lot sida vokse for hvert felt som fikk en
   forklaring. Nå tar den ingen plass før noen spør. */
.click-to-edit__hint-wrap {
    display: inline-flex;
    align-items: center;
    margin-left: var(--space-1);
    vertical-align: middle;
}

.click-to-edit__hint-trigger {
    display: inline-flex;
    align-items: center;
    color: color-mix(in srgb, var(--text-900) 45%, transparent);
    cursor: help;
}

.click-to-edit__hint-trigger:hover,
.click-to-edit__hint-trigger:focus-visible {
    color: var(--text-900);
}

/* Etiketten er VERSALER via .ui-label; det skal ikke smitte over på en
   hel forklarende setning i popoveren. */
.click-to-edit__hint-popover {
    text-transform: none;
    letter-spacing: normal;
    font-weight: 400;
}

/* Badge-kontrast i mørk modus (#10371227376, 05.10.2026). Torleiv: «ta
   badgene også.»

   sand_uis mønster er «-200 bakgrunn + -800 tekst». I lyst tema er det et
   lyst felt med mørk skrift. I mørk modus SNUR skalaen, og de to trinnene
   er da ikke langt nok fra hverandre: man får en middels mettet flate med
   en lys tone oppå.

   MÅLT I MØRK MODUS, slik badgene var:

     grå    4,28   feiler
     grønn  2,69   feiler
     blå    3,36   feiler
     rød    7,54   består
     gul    9,34   består

   Og det er verre enn tallene antyder for den grønne: selv HVIT tekst på
   den bakgrunnen gir bare ~3,5:1. Det holder altså ikke å gjøre skriften
   lysere — flaten må ned.

   -100 BAKGRUNN + -900 TEKST, målt: grå 9,11, grønn 5,35, blå 6,70. Ett
   trinn ut på hver side, samme tanke som sand_uis eget mønster, bare med
   avstanden mørk modus faktisk krever.

   RØD OG GUL SKULLE IKKE RØRES — men ble det likevel. Rettet 08.10.2026.

   Hensikten var å la dem stå: rødskalaen snur ikke i mørk modus, og gul
   har sin egen Stomn-overstyring. Begge består kontrastkravet med sine
   lyse verdier (7,54 og 9,34). Men den nøytrale regelen under står i
   @layer overrides og treffer ALLE merker, mens fargene deres kommer fra
   sand_uis badge.css i @layer components. Lagrekkefølgen slår
   spesifisitet, så den nøytrale vant over begge.

   MÅLT 08.10.2026, mørk modus: gul og rød hadde nøyaktig samme bakgrunn
   som den nøytrale — rgb(59, 65, 69). Et gult varselmerke og et rødt
   avviksmerke så ut som et grått statusmerke for alle som kjører mørkt,
   i hele appen. Kontrasttesten så det ikke: grått på mørkt er godt
   lesbart, det er bare ikke det merket skulle si.

   De to er derfor satt uttrykkelig under, med sine egne lyse verdier.
   badge_colour_distinctness_test er vakten.

   TO BLOKKER, som resten av temaet: mediespørringen for den som følger
   systemet, og speilingen for den som har valgt mørkt uttrykkelig mens
   maskinen står i lyst. Se 01_foundation_and_header.css for hvorfor. */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .ui-badge {
        --badge-bg: var(--text-100);
        --badge-color: var(--text-900);
        --badge-border: var(--text-100);
    }

    :root:not([data-theme="light"]) .ui-badge[data-color="green"] {
        --badge-bg: var(--green-100);
        --badge-color: var(--green-900);
        --badge-border: var(--green-100);
    }

    :root:not([data-theme="light"]) .ui-badge[data-color="blue"] {
        --badge-bg: var(--blue-100);
        --badge-color: var(--blue-900);
        --badge-border: var(--blue-100);
    }

    :root:not([data-theme="light"]) .ui-badge[data-color="yellow"] {
        --badge-bg: var(--amber-200);
        --badge-color: #4d3000;
        --badge-border: var(--amber-200);
    }

    :root:not([data-theme="light"]) .ui-badge[data-color="red"] {
        --badge-bg: var(--red-200);
        --badge-color: var(--red-800);
        --badge-border: var(--red-200);
    }
}

:root[data-theme="dark"] .ui-badge {
    --badge-bg: var(--text-100);
    --badge-color: var(--text-900);
    --badge-border: var(--text-100);
}

:root[data-theme="dark"] .ui-badge[data-color="green"] {
    --badge-bg: var(--green-100);
    --badge-color: var(--green-900);
    --badge-border: var(--green-100);
}

:root[data-theme="dark"] .ui-badge[data-color="blue"] {
    --badge-bg: var(--blue-100);
    --badge-color: var(--blue-900);
    --badge-border: var(--blue-100);
}

:root[data-theme="dark"] .ui-badge[data-color="yellow"] {
    --badge-bg: var(--amber-200);
    --badge-color: #4d3000;
    --badge-border: var(--amber-200);
}

:root[data-theme="dark"] .ui-badge[data-color="red"] {
    --badge-bg: var(--red-200);
    --badge-color: var(--red-800);
    --badge-border: var(--red-200);
}

/* «arvet fra modulen» bak en verdi som ikke er feltets egen
   (08.10.2026). Ordet bærer budskapet — nedtoningen er bare et hint om
   at det er en merknad og ikke en del av verdien. Leses i gråtoner og
   av den som ikke skiller fargene, siden det STÅR hva det er.
   --text-700 og ikke noe svakere: merknaden er det eneste som skiller
   et arvet felt fra et utfylt, og den må være lesbar i begge temaer. */
.field-inherited {
    font-size: 0.8em;
    color: var(--text-700);
    white-space: nowrap;
}

/* GODKJENN OG GÅ TIL DIFF I LAGREBÅNDET (#10373828817, 06.10.2026).

   Står til VENSTRE i båndet, foran Lagre. .save-actions er flex med
   justify-content: flex-end, så uten margin-right: auto ville de to
   knappene klistret seg inntil Lagre og lest som én gruppe — og Godkjenn
   og Lagre må aldri kunne forveksles. Luften mellom dem er budskapet. */
/* GODKJENNINGEN STÅR TIL HØYRE, som på dokumentene (Torleiv
   16.10.2026: «tilpass slik at godkjenning og UI er likt for ulike
   elementer i Stomn» og «plassering av knapper osv»).

   Den sto til VENSTRE (margin-right: auto), med Lagre ytterst til
   høyre. Det ga mening så lenge Lagre alltid sto der. Etter at Lagre
   forsvinner når ingenting er endret, sto Godkjenn alene langt ute til
   venstre — mens dokumentenes godkjenningsvisning har Avvis og Godkjenn
   ytterst til høyre. Samme handling, to steder på skjermen.

   Rekkefølgen er den samme som der: mildest til sterkest, og den
   sterkeste ytterst der blikket lander. Alle seks typene (tiltak,
   risiko, avvik, aktiva, leverandør, revisjon) bruker samme partial, så
   denne ene regelen ensretter dem alle. */
.approval-actions {
    display: flex;
    align-items: center;
    gap: var(--space-sm, 0.5rem);
    margin-inline-start: auto;
}

/* Kommer Lagre fram, skal den ikke leses som en del av godkjenningen:
   luften mellom dem er budskapet (approval_in_save_bar_test krever minst
   24px). */
.approval-actions + * {
    margin-inline-start: var(--space-6, 1.5rem);
}

/* Og når Lagre er skjult, skal heller ikke beholderen rundt den ta
   plass — ellers står marginen over igjen og skyver godkjenningen 24px
   inn fra kanten for ingenting. */
.save-actions > :has(> .save-actions__skjult) {
    display: none;
}

/* Lenken bærer .ui-button, men en <a> arver ikke knappens egen
   linjejustering. Uten dette står «Godkjenn» noen piksler høyere enn
   «Gå til diff» ved siden av — målt, ikke antatt. */
.approval-actions .approve-button {
    display: inline-flex;
    align-items: center;
}

/* Mobil: båndet er smalt, og tre knapper på rad presser Lagre ut.
   Knappene stables ikke — de krymper, og teksten er kort nok. */
@media (max-width: 560px) {
    .approval-actions {
        gap: var(--space-xs, 0.25rem);
    }
}

/* SPRÅKPARET ØVERST PÅ TJENESTEKORTET (#10398652829, 13.10.2026).
   Torleiv: «med språklenke mellom, både internt i systemet og ved
   presentasjon».

   Over dokumentasjonen, ikke under: den som leser Infoskjermens felter
   skal vite at PinToMind sier det samme FØR han leser dem — ellers
   oppdages det ikke at de to har begynt å si forskjellige ting. */
.service-language-pair {
    margin: 0 0 var(--space-3);
    font-size: var(--text-size-sm);
    color: color-mix(in srgb, var(--text-900) 78%, transparent);
}

.service-language-pair__line {
    display: flex;
    align-items: baseline;
    gap: var(--space-2);
    margin: 0;
}

/* Avvikene står under lenka, ikke ved siden av: de er en liste som kan
   bli lang, og den som bare skulle hoppe til søsteren skal ikke måtte
   lese forbi dem. */
.service-language-pair__drift-heading {
    display: flex;
    align-items: baseline;
    gap: var(--space-2);
    margin: var(--space-2) 0 0;
}

.service-language-pair__drift {
    margin: var(--space-1) 0 0;
    padding-left: 1.2em;
}

.service-language-pair__drift li {
    margin-bottom: 0.15rem;
}

/* LEGG TIL OPPGAVE PÅ ET OBJEKT (#10398858028, 13.10.2026).
   Torleiv: «bruker må kunne legge til todo på element.»

   Én linje, tre kontroller: tittel tar plassen, frist er smal, knappen
   til slutt. Bryter på mobil — tre felt ved siden av hverandre under
   420 px blir uleselig. */
.linked-tasks-new {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    align-items: center;
    margin-top: var(--space-3);
}

.linked-tasks-new__title {
    flex: 1 1 14rem;
}

.linked-tasks-new__due {
    flex: 0 0 auto;
    width: auto;
}

/* PLASSERING I AKTIVALISTA (#10401182267, 13.10.2026).

   Målt ved 1280 px: I-001 lister åtte systemer i et felt på 200 px, og
   raden ble 205 px høy mot naboenes 51. Med 57 aktiva er det ni tusen
   piksler skrolling for en liste man skal kunne skumme.

   To linjer, så raden puster litt når teksten er middels lang, men ikke
   sprenger lista når den er lang. Hele teksten ligger i popoveren. */
.asset-location-wrap {
    position: relative;
    display: inline-block;
    max-width: 100%;
}

.asset-location {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    cursor: help;
}

/* position: fixed og ikke absolute: tabellens egen overflow ville ellers
   klippet popoveren for de nederste radene — samme grunn som
   risikomatrisens celler. hover_popover_controller plasserer den. */
.asset-location-popover {
    position: fixed;
    z-index: 100;
    display: none;
    max-width: 28rem;
    padding: var(--space-2) var(--space-3);
    border: var(--card-border);
    border-radius: var(--card-radius);
    background: var(--card-bg);
    box-shadow: 0 4px 16px rgb(0 0 0 / 15%);
    font-size: var(--text-size-sm);
    line-height: 1.5;
}

/* KØEN: «hva mangler noe?» (#10399125156, 14.10.2026).

   Gruppene er <details>, så rådgiveren kan se alle overskriftene først
   og åpne den han vil ta. Med 90 dokumenter uten eier er det forskjellen
   på en liste man går gjennom og en man lukker igjen. */
.review-queue__group {
    margin-top: var(--space-3);
    padding: var(--space-3) var(--space-4);
    border: var(--card-border);
    border-radius: var(--card-radius);
    background: var(--card-bg);
}

.review-queue__summary {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    cursor: pointer;
    /* list-style: none fjerner nettleserens egen trekant, som ikke lar
       seg style og som kolliderer med merket foran teksten. */
    list-style: none;
}

.review-queue__summary::-webkit-details-marker {
    display: none;
}

.review-queue__label {
    font-weight: 600;
}

/* En matrisecelle som filtrerer (#10401182267, 14.10.2026). Peker og
   hover sier at den gjør noe — uten det ser den ut som et tall. */
.risk-matrix__cell--clickable {
    cursor: pointer;
}

.risk-matrix__cell--clickable:hover,
.risk-matrix__cell--clickable:focus-visible {
    outline: 2px solid var(--text-900);
    outline-offset: 1px;
}

/* ERKLÆRING OM ANVENDELIGHET (#10408523124, 16.10.2026).

   93 rader er en LESETABELL, ikke en liste man skummer: en revisor går
   nedover og slår opp ett nummer. Derfor tette rader, tydelige
   kolonneskiller og et nummer som ikke brekker.

   Samme vannrette rulling som de rike tabellene fikk i dag: fem
   kolonner med setningslange begrunnelser får ikke plass på en telefon,
   og da skal den rulle framfor å klemme. Se kommentaren i
   04_document_layout_and_sheet.css for hvorfor en wrapper med
   overflow-x alene ikke holder — tabellen må få lov til å bli bredere
   enn beholderen. */
/* SoA-ene BRUKER HUSTABELLEN (.compliance-overview-table), så det som
   sto her — egen wrapper, egne rammer, egen tetthet — er borte. Torleiv,
   16.10.2026: «litt for bred / tabellen må være hvit, samme uttrykk som
   f.eks. lev.reg».

   Den gamle hadde inline-size: max-content, altså «så bred som
   innholdet krever». Det er riktig for en tabell med setningslange
   celler på en telefon, og feil for en skrivebordsskjerm, der den bare
   ble bred. Hustabellen har width: 100% med en min-width-bunn, og den
   fantes før jeg skrev min egen.

   Nummerkolonnen står igjen: den er SoA-ens egen, og PDF-malen styler
   den på samme klassenavn. */
.soa-table__number {
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}
