/* Root design tokens (colors/spacing/radii/text-size scale), font setup, global background/scrollbar reset, sticky page header/breadcrumb/nav, brand logo.
   Split out of theme.css (original lines 1-442) — 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 {
/*
 * Stomn theme overrides. Loaded AFTER sand_ui's stylesheet (see app/views/shared/_head.html.erb) —
 * both define :root with equal specificity, so load order decides which wins. This file must
 * always be the last stylesheet loaded for its overrides to take effect.
 */

/*
 * Torleiv, 2026-08-19 ("premium refresh" — maksimalt pedagogisk, lettbrukt,
 * lettlest, moderne; premium men varm og myk): the app's neutral hue was a
 * cool blue (210deg), landing every grey/border/shadow with a faint "bank
 * app" cast — at odds with the warm, human tone the rest of the theme
 * (green "encouraging" signal color, human copy) was already going for.
 * Warmed to a soft stone/paper hue instead — every --ui- and --text- token
 * in sand_ui/colors.css derives from --hue, so this one change recolors
 * every neutral surface, border, and muted-text tone across the whole
 * app at once, without touching the signal green (untouched, already
 * deliberately chosen — see its own comment below) or the "no serif
 * headings" decision (also untouched — see fb2b986, a considered call,
 * not something this pass revisits). Per sand_ui's own style guide,
 * prefer overriding tokens over rewriting rules.
 */
:root {
    --hue: 32deg;
    --saturation: 16%;
    /* Torleiv, 2026-08-19: replaced by the official grafisk profil
       ("Vendepunktet") delivered today — Bein (#F4F0E8), the profile's
       own "papirflaten" (paper surface) color, close enough to last
       night's guessed warm stone (#F7F4EF) that nothing else needed to
       shift to accommodate it. */
    --background-color: #F4F0E8;
    /* Torleiv, 2026-08-19 ("gå for blekk"): the grafisk profil is explicit
       that its one brand accent (Oksblod, #7A2E30) must NEVER appear in
       the product's own interface — only status colors (red/yellow/green)
       are allowed to carry meaning there, so a "signal" color can't be a
       brand hue at all. Blekk (#1A1C1B, the mark's own color) instead —
       replaces 2026-08-16's green (#1B7A4F, chosen specifically to avoid
       black buttons feeling "bank-aktig"). Live-compared both on real
       pages before this call: Blekk reads as calm/confident given the
       warmer, less clinical grey scale everything else already sits on
       now, not cold the way the old pure-black --ui-800 attempt did.
       One accepted tradeoff: a few accent-as-affordance spots (the
       Sidefelt pill, notice banners) read quieter now that the accent
       doesn't contrast against near-black body text the way green did —
       flagged for a follow-up pass if it turns out to matter in practice,
       not blocking this decision. --signal-color-tint is Sand (#DED7C9,
       the profile's own "felt/tabellstriper" tone) rather than a
       synthetic near-white tint, so it still reads as a deliberate fill
       against Bein instead of nearly disappearing. */
    --signal-color: #1A1C1B;
    --signal-color-tint: #DED7C9;

    /* sand_ui's own --signal (used directly by native checkbox/radio
       accent-color, .bg-signal, .text-signal, etc.) is a separate token from
       --signal-color above and was never overridden — every native checkbox
       in the app was still Favo's default orange regardless of --hue. */
    --signal: var(--signal-color);
    --signal-light: var(--signal-color-tint);
    /* Hover shade for .solid.preferred (see below) — same darkening ratio
       applied to the new green as the old blue's --signal-dark had to
       --signal-color. */
    --signal-dark: #124F33;

    /* Torleiv, 2026-08-10: sand_ui's own --solid-color default is pure
       #000 — every plain .solid button with no ui-NNN modifier (Lagre,
       Opprett, Bekreft og aktiver, ...) rendered stark black. First pass
       used --ui-800 (dark charcoal) — still read as "black" at a glance
       even though it's technically lighter than #000. Second pass used
       --ui-500 (a --hue-tinted grey) to distinguish a plain solid button
       from the ONE emphasized action on its screen (.solid.preferred,
       below) — but that grey carried a blue cast from --hue, which read
       as "bank-like" (Torleiv, 2026-08-16: "en oppmuntrende grønnfarge i
       stedet for bank-aktig blåfarge"). Now the same --signal-color as
       .solid.preferred: every plain solid button (Godta og fortsett,
       Lagre, Opprett, ...) is that green, not just the one emphasized
       action — a deliberate tradeoff of the earlier grey/green two-tone
       hierarchy for a single, consistently encouraging button color. */
    --solid-color: var(--signal-color);

    /* Spacing scale — use these instead of ad-hoc rem values, so rhythm stays consistent. */
    --space-1: 0.25rem;
    --space-2: 0.5rem;
    --space-3: 0.75rem;
    --space-4: 1rem;
    --space-5: 1.25rem;
    --space-6: 1.5rem;
    --space-8: 2rem;
    /* Lagt til 16.09.2026 (#10309415397, «mer padding» på
       leverandørsida). Skalaen stoppet på 2rem, som er .ark sin egen
       padding — det fantes altså ikke noe steg over «arkets standard»
       å be om uten å finne på et tall. Nå gjør det det. */
    --space-10: 2.5rem;

    /* Torleiv, 2026-08-19 ("rydde i ark-bredde... finn tre standardbredder
       for ark"): the two widths every "ark" (.document-sheet/.ark) page
       actually used already, just never named — a document's own
       .document-focus wrapper at 900px, and the profile/2FA/access-list
       forms' shared .profile-edit__box at 480px (already deliberately
       tuned there, see that rule's own comment: tried 640/900, settled
       back on 480). The third "width" the todo names, full-width-with-
       sidefelt-open, isn't a fixed third number — it's --content-width
       itself reflowing narrower as .app-shell's flex row gives the
       sidebar its own room, which .document-focus already did correctly;
       naming the two real widths just lets every other page (Binder,
       Mine dokumenter, module TOCs — see .workspace-dashboard below) line
       up with the SAME two, instead of each drifting to its own
       accidental width from whatever ancestor happened to constrain it. */
    --content-width: 900px;
    --content-width-narrow: 480px;

    /* Shared card look: one radius/border everywhere instead of several slightly different ones. */
    --card-radius: 16px;
    --card-border: 1px solid color-mix(in srgb, var(--text-900) 8%, transparent);
    --card-bg: #fff;
    --card-bg-muted: var(--background-color);
    /* Torleiv, 2026-08-19 (premium refresh): cards had a border but zero
       shadow anywhere in the app — flat and a little clinical against the
       new warm background. A soft, low-spread shadow (barely visible at a
       glance, felt more than seen) gives every .ui-box/.card real
       presence without the heavy drop-shadow "card game" look overdesign
       tips into. Kept as its own token rather than baked into .ui-box's
       existing rule so any surface can opt in with one line. */
    --card-shadow: 0 1px 2px rgba(28, 25, 20, 0.04), 0 8px 24px -12px rgba(28, 25, 20, 0.12);
    /* Same shadow and ::backdrop tint on every centered native <dialog>
       (confirm, nav-gear, system-settings, global search) — both were
       copy-pasted 4 times as raw values before these tokens existed. */
    --dialog-shadow: 0 12px 40px rgba(28, 25, 20, 0.18);
    --dialog-backdrop: rgba(28, 25, 20, 0.35);

    /* The rest of the app's small radii, named instead of repeated as loose
       px values (see /stilguide) — --card-radius above stays as its own
       thing since renaming it would ripple through every existing usage. */
    --radius-sm: 6px;
    --radius-md: 10px;
    --radius-lg: 12px;
    --radius-pill: 999px;

    /* Status colors — previously 3-4 near-duplicate hex values per status
       scattered across the file (e.g. #9a2f2f, #8a2c2c, #B3261E all meaning
       "danger text"). One value per status now; the color-wheel/rainbow
       accents elsewhere (module-card picker, "no color" swatch) are a
       decorative palette, not status colors, and are intentionally left
       alone. */
    --danger-color: #B3261E;
    --success-color: #1e6b30;
    /* --warning-color kom til 21.09.2026. Den fantes ikke, og derfor grep
       leverandørprikken til rå --amber-600 fra sand_ui-paletten — som gir
       1.58:1 mot den varme bakgrunnen, altså en «venter»-prikk som knapt er
       synlig i lys modus (standardtemaet). Ingen verdi i amber-skalaen duger:
       den mørkeste, --amber-900, kommer bare til 2.46:1. #996000 gir 4.59:1
       og leses fortsatt som gyllen, ikke brun. */
    --warning-color: #996000;

    /* Text color scale — six near-duplicate grays (#111/#444/#666/#777/#888/#aaa)
       used loosely (and inconsistently — existing var(--text-500, ...) call
       sites alone use #666, #777, AND #888 as their fallback) across the
       file for the same handful of "weights". Values below are chosen to
       match each step's DOMINANT existing fallback, not an average — see
       call sites via `grep "text-NNN, #"` if a specific spot looks off
       after this lands. #777 is dropped (redundant between 666 and 888).*/
    /* Torleiv, 2026-08-19 ("gå for blekk"): --text-900 and --text-700 are
       now Blekk and Grafitt exactly — the grafisk profil already names
       those two for "merket, overskrifter, brødtekst" and "dempet tekst,
       etiketter, metadata" respectively, so no guessing needed for either
       end of the scale. --text-600/500/400 aren't in the 5-color profile
       at all (it's deliberately a lean palette, not a full gray ramp) —
       interpolated between Grafitt and Sand (#DED7C9, the profile's next
       lightest neutral) to keep a smooth scale rather than a visible jump
       at the two named steps. */
    --text-900: #1A1C1B;
    --text-700: #54595A;
    --text-600: #7D7F7B;
    --text-500: #A09E97;
    --text-400: #C2BEB3;

    /* Font-size scale — the file had 19+ distinct one-off rem values for
       body/UI text (0.74rem through 1.15rem) with no shared vocabulary.
       These five steps cover the actual clusters found; migrating every
       existing declaration to the nearest step is a separate, deliberate
       pass (see /stilguide) rather than a silent blanket resize here. */
    --text-size-xs: 0.75rem;
    --text-size-sm: 0.85rem;
    --text-size-base: 0.9rem;
    --text-size-lg: 1rem;
    --text-size-xl: 1.05rem;
}

/* Basecamp #10273056977 (Torleiv, "Gå gjennom hele appen og tilpass slik
   at dark mode funker"). Root cause of the reported breakage: every token
   above (--background-color, --signal-color, --text-900/700/600/500/400,
   --card-bg/--card-bg-muted) is a literal hex from the brand palette with
   NO dark counterpart anywhere in the codebase — confirmed by grep, only
   one definition of each exists. sand_ui's OWN tokens (--bg-color,
   --text-color, --border-color, the --ui-NNN / --text-NNN HSL scale in
   sand_ui/colors.css) already correctly invert under prefers-color-
   scheme — that's why the screenshots showed a PATCHWORK: components
   using sand_ui's tokens directly (the auth-card, the tenant picker) went
   dark, while the page background and anything using Stomn's own
   brand-literal tokens (headings, buttons) stayed stuck in light mode's
   colors — including, on unstyled text relying on the browser's own
   default `color` (CanvasText), REAL near-invisible text: color-scheme:
   light dark is already set (sand_ui/reset.css), so CanvasText itself
   auto-lightens in dark mode even with zero author CSS — pale text
   sitting on a background that never got the matching dark treatment.
   This block is that treatment, added at the single root :root level so
   every one of the ~1050 existing var(--background-color)/var(--text-9NN)/
   var(--signal-color) call sites across the app inherits it for free.

   Values are grounded in the brand document itself ("Logo og grafisk
   profil" v1.0, read from the workspace's own ActionText body — see
   reference_stomn_brand_document memory) rather than invented: it ships
   an explicit "Merke — bein på blekk" asset for dark surfaces — Blekk
   (#1A1C1B) as the dark background, Bein (#F4F0E8) as the light mark/text
   on it. This block is exactly that swap applied to the app's own token
   set, not a new palette. The muted-text scale (--text-700..400) mirrors
   light mode's own Blekk→Sand progression as a Bein→Blekk color-mix, and
   --signal-color-tint/--signal-dark (subtle fills, button hover) follow
   the same logic: a light-mode Sand-toned tint would read as a jarring
   near-white blob on a mostly-dark page, so these are computed relative
   to the new dark --background-color instead of reusing the literal
   light-mode Sand hex. */
/* #10278596584 follow-up (Torleiv: "Legg inn på 'meg': valg mellom lys,
   mørk og auto"): a person can now override the OS-level preference via
   Person#theme_preference, rendered as a data-theme="light"/"dark"
   attribute on <html> (see layouts/application.html.erb) — "auto" (the
   default) renders no attribute at all, leaving this exact media query
   as the sole source of truth, unchanged from before this feature
   existed. :not([data-theme="light"]) is the one addition to the media
   query itself: without it, someone who explicitly chose "light" while
   their OS is set to dark would still get this block's dark tokens,
   since a plain :root selector doesn't know about the attribute at all.
   The second, non-media block below is the mirror case — someone who
   explicitly chose "dark" needs these tokens applied even when their OS
   is in light mode, where the media query's own condition is false and
   so never fires regardless of the attribute. Both blocks carry the
   identical token list on purpose (plain CSS here, no preprocessor to
   share a mixin) — keep them in sync if either changes. */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        --background-color: #1A1C1B; /* Blekk */

        --text-900: #F4F0E8; /* Bein */
        --text-700: color-mix(in srgb, #F4F0E8 75%, #1A1C1B 25%);
        --text-600: color-mix(in srgb, #F4F0E8 55%, #1A1C1B 45%);
        --text-500: color-mix(in srgb, #F4F0E8 35%, #1A1C1B 65%);
        --text-400: color-mix(in srgb, #F4F0E8 15%, #1A1C1B 85%);

        /* Bein instead of Blekk — a Blekk button on a now-Blekk page
           background would vanish; the light-ink-on-dark-paper mirror of
           the light theme's own dark-ink-on-light-paper button. */
        --signal-color: #F4F0E8;
        --signal-color-tint: color-mix(in srgb, #1A1C1B 82%, #F4F0E8 18%);
        --signal-dark: color-mix(in srgb, #F4F0E8 85%, #1A1C1B 15%);
        /* #1e6b30 er valgt mot papir. Mot Blekk blir den for nær
           bakgrunnen til å lese som en flate. */
        --success-color: #2f9c56;
        /* --danger-color hadde INGEN mørk verdi og sto på #B3261E i begge
           temaer: 2.62:1 mot blekk, under kravet overalt den brukes.
           #f43f5e er --red-500 fra paletten og gir 4.67:1. */
        --danger-color: #f43f5e;
        --warning-color: #ff6f00; /* --amber-900, 6.14:1 */

        --card-bg: var(--background-color);
        --card-bg-muted: color-mix(in srgb, #1A1C1B 92%, #F4F0E8 8%);
    }
}

:root[data-theme="dark"] {
    color-scheme: dark;
    --background-color: #1A1C1B; /* Blekk */

    --text-900: #F4F0E8; /* Bein */
    --text-700: color-mix(in srgb, #F4F0E8 75%, #1A1C1B 25%);
    --text-600: color-mix(in srgb, #F4F0E8 55%, #1A1C1B 45%);
    --text-500: color-mix(in srgb, #F4F0E8 35%, #1A1C1B 65%);
    --text-400: color-mix(in srgb, #F4F0E8 15%, #1A1C1B 85%);

    --signal-color: #F4F0E8;
    --signal-color-tint: color-mix(in srgb, #1A1C1B 82%, #F4F0E8 18%);
    --signal-dark: color-mix(in srgb, #F4F0E8 85%, #1A1C1B 15%);
    --success-color: #2f9c56;
    /* Samme to som over — begge mørk-motorene må treffes. */
    --danger-color: #f43f5e;
    --warning-color: #ff6f00; /* --amber-900, 6.14:1 */

    --card-bg: var(--background-color);
    --card-bg-muted: color-mix(in srgb, #1A1C1B 92%, #F4F0E8 8%);
}

/* #10278596584 hotfix (Torleiv's own screenshot, live prod: washed-out,
   near-invisible text on /favo/suppliers): sand_ui/reset.css sets a
   blanket `:root { color-scheme: light dark; }`, which lets the BROWSER
   itself auto-invert any UA-default color (unstyled text using the
   browser's own CanvasText, native form controls, scrollbars) purely
   off the OS's prefers-color-scheme — a completely separate mechanism
   from the CSS custom properties above, which data-theme has no say
   over. Someone with an explicit "light" choice AND an OS set to dark
   got exactly this: Stomn's own tokens correctly forced light (cream
   background), but anything relying on native color-scheme-driven
   resolution still went dark-mode-light-text, i.e. near-white text on
   the still-cream background. Pinning color-scheme to match each
   explicit choice closes that gap; "auto" is deliberately left alone
   (no rule here), preserving sand_ui's own `light dark` for that case,
   exactly as before this feature existed. */
:root[data-theme="light"] {
    color-scheme: light;
}

@font-face {
    font-family: "Instrument Serif";
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url("/assets/Instrument-Serif/InstrumentSerif-Regular.ttf") format("truetype");
}

/* Modern, human, highly-legible system font instead of sand_ui's Verdana/Helvetica default. */
:root {
    --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;

    /* No serif headings anywhere — sand_ui's h1/h2/h3 (and .font-serif) all
       derive from this token, so overriding it here (rather than rewriting
       each rule) collapses every heading onto the sans body face at once. */
    --font-serif: var(--font-sans);
}

html,
body,
.ui-page-layout,
.ui-page-layout .outer-background,
.page-frame,
body.striped-bg {
    background-color: var(--background-color);
    background-image: none;
}

/* Torleiv, 2026-08-15: the real cause of a second kind of Sidefelt width
   jitter — some pages have enough content to need a vertical scrollbar,
   others don't, and a page's own scrollbar eats real layout width when
   it's actually rendered. Reserving that space ALWAYS (whether or not
   this particular page happens to scroll) means every page's available
   content width is identical, sidebar open or not, scrollbar needed or
   not — nothing shifts when navigating between a short and a long page. */
html {
    scrollbar-gutter: stable;
}

/* Torleiv, 2026-08-16, follow-up to the jitter fix above: reserving the
   gutter kept the WIDTH stable, but the visible scrollbar track itself
   still appears/disappears depending on whether a given page happens to
   scroll — Torleiv still saw that as "trangt" (tight). Hiding the native
   track entirely (Firefox via scrollbar-width, WebKit via the pseudo
   below) removes that last visual difference: the reserved gutter is
   now always just empty space, whether or not the page scrolls.
   Scrolling itself still works via wheel/trackpad/keyboard — only the
   visible bar is gone, not the functionality. */
html {
    scrollbar-width: none;
}

html::-webkit-scrollbar {
    display: none;
}

/* Matches Basecamp's dashboard/page column width — sand_ui's 900px default
   read narrower than Basecamp's, and an earlier 760px overcorrected. */
.page-body {
    max-width: 1040px;
}

/* Torleiv, 2026-08-19 (premium refresh): sand_ui's base .ui-box has a
   border but no shadow at all — every card in the app (home's Selskapet
   hero, the Moduler grid, document metadata cards, ...) sat perfectly
   flat against the page. One soft --card-shadow (see its own token
   comment) on the base class gives all of them a consistent, gentle
   lift — .elevation-1/2/3 (already used a few places, e.g. the login
   card) still win where a page explicitly asks for more depth than
   this, since a later class with equal specificity here would need its
   own !important otherwise — checked: none currently combine .ui-box
   with an .elevation-* AND expect zero shadow, so this is additive, not
   a conflict. */
.ui-box {
    box-shadow: var(--card-shadow);
}

/* Consistent gap between the breadcrumb (last thing in .page-header) and
   the first element of every page's actual content — sand_ui's
   .page-content only has left/right padding, none on top, so pages sat
   flush against the breadcrumb. This is the one place to adjust that gap
   app-wide, rather than each page adding its own top margin/padding. */
.page-content {
    padding-top: var(--space-6);
}

/* Remove sand_ui's vertical frame borders and the header/body seam — one continuous
   background instead of a visibly "boxed" top bar and side gutters. */
.page-frame {
    border-left: none;
    border-right: none;
}

.page-header {
    border-bottom: none;
    background: var(--background-color);
    /* Promotes this sticky element to its own compositing layer — without
       it, a brief white seam (the sheet's own background painting through
       for a frame or two) can flash at the very top of the viewport while
       actively scrolling, before the sticky repaint catches up. */
    will-change: transform;
    /* Full-bleed: escape .page-frame's 1300px cap AND .outer-background's own
       20px horizontal padding (sand_ui's page-layout.css, active from
       600px up) so Hjem/søk/bruker can pin to the true viewport edges,
       independent of the centered content column's width.

       Torleiv, 2026-08-15 (screenshot, after trying the "shrink with the
       sidebar" version first): the header must stay "frozen" — always
       full 100vw width, icons always pinned to the TRUE right edge,
       completely unaffected by the sidefelt drawer opening or closing.
       WIDTH is therefore a flat 100vw again, not 100vw - sidebar-width.

       But margin-left still has to know about --sidebar-width: this
       header's containing block is .page-frame, which lives INSIDE
       .app-shell's shrinking .ui-page-layout — .page-frame's own width
       (and therefore where "50%" lands) genuinely changes when the
       drawer opens, even though the header's own width doesn't. Ignoring
       that (a flat `calc(50% - 50vw)`) put the header's left edge at
       -180px instead of 0 the moment the drawer opened — verified via
       getBoundingClientRect(), not just assumed. This computes the
       header's actual static starting position — outer-background's own
       20px padding, plus .page-frame's own centering offset within that
       (only nonzero once the available width exceeds the 1300px cap) —
       and cancels it out exactly, landing the header at the true edge
       (x: 0) regardless of whether the sidebar has shrunk .page-frame. */
    /* dvw, not vw (Torleiv, mobile screenshot, 2026-09-06: "header-
       seksjonen er litt for langt til høyre" — the header's right-
       anchored icons spilling past the true right edge on a real
       phone). 100vw resolves against the LARGEST possible viewport on
       mobile Safari (browser-chrome-collapsed state), which can be
       wider than the actual visible viewport at the moment this is
       painted — this box then renders wider than the screen, and
       .header-actions' own right: 0 (below) lands past the true right
       edge instead of flush with it. Couldn't reproduce in this
       session's own emulated testing (a known limitation — mobile
       Safari's viewport-unit quirks don't show up in Chromium
       devtools), but dvw exists specifically to resolve against
       whichever viewport is ACTUALLY rendered right now, sidestepping
       the ambiguity entirely — a strict improvement here regardless of
       the exact trigger, and well-supported (Safari 15.4+, 2022). The
       max(0px, ...) clause below only ever matters above ~1340px
       (desktop), so this is mobile-only in effect. */
    width: 100dvw;
    margin-left: calc(-20px - max(0px, (100dvw - var(--sidebar-width) - 1340px) / 2));
    /* Above .my-tasks-panel__content's own z-index: 110 — since this
       header is "frozen" (always full width, see above) it overlaps the
       drawer's top edge whenever the drawer is open; without outranking
       it here, the drawer would paint over the header and hide Hjem/
       søk/bruker again, the exact bug this whole redesign started from. */
    z-index: 120;
}

/* #10277141488/#10276047895 (Torleiv, real-iPhone screenshot 2026-09-07
   kl. 22.42, red-boxed): "Hjem" sits flush against — and the header's
   right edge falls short of — the true viewport edges, unlike every
   other element on the page (13px page-content gutter). Measured, not
   guessed: getBoundingClientRect() on a real mobile viewport put
   .page-header-grid's own left edge at -10px, and .header-nav__home's
   rendered box at -10px too — both actually PAST the true left edge.

   Root cause: the -20px flat term in .page-header's own margin-left
   above exists specifically to cancel .outer-background's 20px
   horizontal padding (sand_ui/page-layout.css) — but that padding is
   itself only active `@media (min-width: 600px)`. Below 600px there is
   no padding to cancel, so the header overshoots left by that same
   20px unconditionally, and — since width stays a flat 100dvw
   regardless — the right edge falls exactly as far short of the true
   edge as the left edge overshoots it. This is a DIFFERENT bug than
   the 100vw->100dvw viewport-unit fix above (that one is about WIDTH
   resolving against the wrong viewport; this one is a plain
   breakpoint mismatch in the MARGIN math) — both happened to be
   reported as "header positioned wrong on mobile", but the earlier fix
   never touched this term at all. No sidebar-drawer term needed here
   either (that only ever matters above ~1340px) — margin-left is
   simply 0 below the breakpoint the -20px term was built to match. */
@media (max-width: 599px) {
    .page-header {
        margin-left: 0;
    }
}

.page-header-grid {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-2);
    padding: var(--space-4) var(--space-2) var(--space-2);
}

.header-bar {
    position: relative;
    display: flex;
    justify-content: center;
    align-items: center;
    width: 100%;
    min-height: 40px;
}

/* Vertically centered the same way .header-brand's logo already is
   (.header-bar's own flex align-items: center) — top: 0 previously
   pinned this to the bar's own top edge instead, sitting visibly higher
   than the logo (Torleiv, 2026-08-10). */
.header-nav {
    position: absolute;
    left: 0;
    top: 50%;
    transform: translateY(-50%);
}

/* Matches the soft-grey rounded hover every other header control already
   has (search icon, avatar) — negative margin cancels the extra padding
   out of the layout, so the link's own position doesn't shift. */
.header-nav__home {
    display: inline-flex;
    align-items: center;
    padding: var(--space-1) var(--space-2);
    margin: calc(var(--space-1) * -1) calc(var(--space-2) * -1);
    border-radius: var(--radius-md);
    /* A step up from the ambient body text (Torleiv, 2026-08-10: "litt
       større") — was unset/inherited before, reading noticeably smaller
       than the icon next to it. */
    font-size: var(--text-size-lg);
    font-weight: 400;
    color: inherit;
    text-decoration: none;
    transition: background 0.15s ease;
}

.header-nav__home:hover {
    background: color-mix(in srgb, var(--text-900) 8%, transparent);
}

.header-nav__home i {
    font-size: var(--text-size-xl);
}

/* Same centering fix as .header-nav above, same reason. */
.header-actions {
    position: absolute;
    right: 0;
    top: 50%;
    transform: translateY(-50%);
}

.header-brand {
    display: flex;
    justify-content: center;
    /* Torleiv, 2026-08-15: the logo centered on the header's own full
       100vw width (see .page-header's "frozen" comment), but the real
       page content below lives inside .ui-page-layout, which the sidebar
       spacer narrows — so its own true center sits --sidebar-width/2 to
       the LEFT of the viewport's center whenever the drawer is open. A
       margin-right on this single centered flex item shifts ITS centered
       position left by exactly that same half-width, without touching
       .header-nav/.header-actions (still absolutely positioned flush to
       the header's true left/right edges — unaffected, and correctly so,
       since those are meant to stay at the true viewport edges). Verified
       live: with the drawer open, this lands the logo's own visual
       center within ~1px of .document-layout's real center. */
    margin-right: var(--sidebar-width, 0px);
    transition: margin-right 0.2s ease;
}

/* Torleiv, 2026-08-17 (mobile audit, screenshot): .header-brand is
   centered on the header's full width while .header-nav ("Hjem") and
   .header-actions (Sidefelt/søk/avatar) are pinned absolute to its true
   left/right edges — a layout that only avoids collision when the
   viewport is wide enough to fit all three side by side. .header-actions
   alone measures ~226px, so even shrinking the brandmark to icon-only
   still collides up to ~486px — nowhere near enough headroom on a real
   phone. Hiding it below 600px (this file's usual mobile breakpoint) is
   the only fix that holds regardless of exact width, and it's a genuine
   duplicate, not a loss: .svg-logo and .header-nav__home both link to
   the same workspace root, so "Hjem" alone still covers the ONE thing
   this mark also does. */
@media (max-width: 600px) {
    .header-brand {
        display: none;
    }
}

/* Same fix, same reason, as .header-brand just above — .header-breadcrumb
   (application.css) is its own separate width:100%/justify-content:center
   flex row, not a descendant of .header-bar, so it needs the identical
   correction independently. padding-right (not margin, since this
   container has no absolutely-positioned children to disturb) shrinks
   its own centering box the same way. */
.header-breadcrumb {
    padding-right: var(--sidebar-width, 0px);
    transition: padding-right 0.2s ease;
    /* Torleiv, 2026-08-17 ("Lag litt mer luft under brødsmulene, slik at
       malen har plass til knapper"): first bump (--space-2) was still
       "litt lite" per his follow-up screenshot, so doubled it. This
       sits inside the app-wide sticky header, so its height feeds
       --page-header-height (sticky_offset_controller.js) and changes
       every page's sticky offset, not just one. Flag if this still
       isn't enough once an actual button row lands here. */
    margin-bottom: var(--space-4);
}

/* sand_ui's own .page-header-grid .svg-logo rule (page-layout.css) applies
   an asymmetric 5px/20px left/right padding meant for ITS OWN 3-column
   grid header — an ancestor .page-header-grid wrapper still exists further
   up even though this custom header doesn't use that grid, so the leaky
   descendant selector still reaches in here. That padding shifted the
   shield+wordmark ~7-8px left of the breadcrumb's true center below it.
   Matching specificity (two classes) so this wins regardless of stylesheet
   load order. */
.stomn-brandmark {
    display: inline-flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    /* Torleiv, 2026-08-19 ("Logo og skrift i toppen må justeres mot
       hverandre") and again 2026-08-20 (#10222078085, "Logo må følge mal
       ... Nøyaktig lik"): the wordmark's height and this gap are both
       derived from the profile's own combined vannrett-navnetrekk
       geometry (tmp/grafisk-profil/navnetrekk/stomn-navnetrekk-vannrett.svg,
       one shared coordinate space for mark + wordmark) rather than
       eyeballed. In that file the mark is 52.41 units tall, the wordmark's
       cap height is 24.85, and the space between them is 14.87.

       --brandmark-mark-height is the mark's DRAWN height, and everything
       else is a ratio against it, so the lockup can be resized in one
       place without the proportions drifting.

       Why the drawn height and not the icon box: the first pass at this
       (4eec594) scaled both ratios against the icon's 34px CSS box, but
       the mark's viewBox is 56 × 52.41 — wider than tall. A square box
       therefore letterboxes it: the mark renders 34/1.0685 ≈ 31.8px tall,
       not 34px, so both the wordmark (16px) and the gap (9.6px) came out
       ~6 % too large against the mark actually on screen — measured
       2.099 mark-to-cap in the profile vs. 1.988 in the header. The icon
       box below is now the mark's own aspect ratio instead of a square,
       which removes the letterboxing along with the error. */
    --brandmark-mark-height: 32px;
    gap: calc(var(--brandmark-mark-height, 32px) * 14.87 / 52.41);
}

/* Torleiv asked several times (2026-08-15, 2026-08-16) to make the shield
   icon bigger relative to the "stomn" wordmark, and each attempt at
   raising .stomn-brandmark__icon's width/height in application.css
   silently had NO visual effect on the in-app header. Root cause found
   2026-08-16: sand_ui ships its own default logo sizing,
   `.page-header-grid .svg-logo svg { height: 20px; width: auto; }`,
   which has HIGHER specificity (two classes + a type selector) than a
   bare `.stomn-brandmark__icon` class selector — so it always won there,
   regardless of what size was set. The plain selector below still works
   fine on its own everywhere shared/_svg_logo is wrapped by something
   OTHER than `.svg-logo` (login, password reset, tenant picker, 2FA —
   all via sand_ui's own _centered_box partial, which has no competing
   sizing rule). The second selector exists only to also win in the
   `.svg-logo` (app header) context: it matches sand_ui's specificity
   exactly (two classes + a type selector) and, because this file loads
   after sand_ui's own stylesheet, wins that tie. Don't drop it thinking
   it's redundant with the first selector — the header silently loses
   its sizing again without it. */
.stomn-brandmark__icon,
.svg-logo svg.stomn-brandmark__icon {
    display: block;
    /* Basecamp #10273056977 (dark mode): the shield SVG now fills with
       currentColor (see that file's own comment) instead of a hardcoded
       Blekk — this is what it resolves against, so the mark is Blekk on
       Bein in light mode and Bein on Blekk in dark, matching the brand
       document's own "Merke — bein på blekk" dark-surface variant. */
    color: var(--text-900);
    /* The mark's own aspect ratio (viewBox 56 × 52.41), not a square —
       a square box letterboxes the mark and makes its drawn height 6 %
       smaller than the box every other size here is derived from. See
       .stomn-brandmark above. */
    height: var(--brandmark-mark-height, 32px);
    width: calc(var(--brandmark-mark-height, 32px) * 56 / 52.41);
    flex: none;
    /* Never give this element a border-radius. The mark's own geometry is
       flush with three sides of its viewBox — x=4 (left bar), y=5.75 (top
       bar) and x=60 (the top bar's right end) — because the profile is
       explicit that both horizontal lines run OUT of the drawing surface
       ("tidslinjen fortsetter utenfor merket"). A radius clips the box,
       and with the ink sitting on the box edge it clips the ink: a
       border-radius: 5px here (removed 2026-08-20) cut the top bar's
       right end off at an angle, which is what Torleiv reported as the
       mark looking "spisset" in #10222078085. Verified by reconstructing
       both renderings against his screenshot — the clipped one matches
       the screen in that corner, the unclipped one doesn't. */
}

.stomn-brandmark__graphic {
    display: block;
    width: auto;
    /* Basecamp #10273056977 (dark mode): now inlined with a currentColor
       fill (see that file's own comment) instead of a plain <img> with a
       hardcoded Blekk fill — same reasoning as .stomn-brandmark__icon
       above. */
    color: var(--text-900);
    /* The wordmark's cap height is 24.85 of the profile lockup's units
       against the mark's own 52.41 — ~47 % of the mark's height, never
       "almost as tall as the mark" (it was 35px next to a 34px mark
       before 2026-08-19). Derived from the mark's drawn height, so the
       ratio holds whatever --brandmark-mark-height is set to. */
    height: calc(var(--brandmark-mark-height, 32px) * 24.85 / 52.41);
    flex: none;
}

/* stomn-innlasting.svg draws itself entirely in currentColor (so the same
   file works in any theme without a separate dark copy) — this is what it
   resolves against here. Matches the static mark's own hardcoded Blekk
   fill so swapping between the two (turbo_loading_icon_controller.js)
   doesn't shift color. */
.stomn-brandmark__loading-icon {
    color: var(--text-900);
}

/* Hover-to-accent on the shield icon, everywhere it's technically possible
   (Torleiv, 2026-08-14: "Bruk rosa hover alle steder det er mulig, men
   sort der det ikke er mulig") — every render of shared/_svg_logo inlines
   the SVG (see that partial's own comment on why: inline_svg_tag, not
   image_tag, specifically so CSS can reach the <path>), so this isn't
   scoped to the in-app header any more. The only place it stays plain
   black is the favicon/apple-touch-icon — those are static raster/SVG
   files the browser renders on its own with no CSS involved at all.
   Torleiv, 2026-08-16 ("bytt ut rosa med den nye grønnfargen"): swapped
   the hardcoded pink (#E5347D) for var(--signal-color), the same green
   the button/link overhaul earlier this session made the app's one
   accent color — so the logo hover follows that color if it's ever
   retuned again, instead of drifting back out of sync with it. */
.stomn-brandmark__icon path {
    transition: fill 0.15s ease;
}

.stomn-brandmark:hover .stomn-brandmark__icon path {
    fill: var(--signal-color);
}

.header-brand .svg-logo {
    padding: 0;
}


} /* @layer overrides */

/* .text-dense: sekundærtekst som faktisk lar seg lese (#10371227376,
   05.10.2026). Torleiv: «ta text-dense også.»

   sand_ui setter den til --text-300. Målt: 2,08:1 i lyst tema og 3,04:1 i
   mørkt, mot kravet 4,5:1 for 15px. Klassen brukes 133 steder i 72
   visninger, så dette er den enkeltendringen i gjennomgangen som treffer
   bredest.

   HVORFOR IKKE ET NAVNGITT TRINN. Fargestigen har ikke noe som både
   består OG holder seg under brødteksten:

                  lyst    mørkt
     --text-500   2,36    2,98
     --text-600   3,56    5,40   ← fortsatt under kravet i lyst
     --text-700   6,26    8,93   ← dette ER brødteksten, i begge tema

   --text-700 ville altså gjort sekundærtekst identisk med brødtekst, og
   da er den ikke sekundær lenger. Hele poenget med klassen forsvinner.

   EN BLANDING LØSER DET, fordi --text-900 snur med temaet — én verdi
   dekker begge. Målt over sidens egen bakgrunn:

            lyst    mørkt
     60 %   4,32    6,18   ← under kravet i lyst
     62 %   4,60    6,51   ← består, men tynn margin mot 4,5
     65 %   5,05    7,02   ← valgt
     72 %   6,35    8,33   ← lyst er nå MØRKERE enn brødteksten

   65 % består med margin i begge tema og ligger tydelig under
   brødteksten (6,26 og 8,93). Hierarkiet er altså i behold: teksten er
   fortsatt dempet, den er bare ikke lenger uleselig.

   Her og ikke i sand_ui/text.css, så en oppdatering av designsystemet
   ikke stryker rettelsen. Samme grep som badgene og avataren fikk. */
.text-dense {
    color: color-mix(in srgb, var(--text-900) 65%, transparent);
}

/* SEKSJONSOVERSKRIFTENE LESTES IKKE SOM OVERSKRIFTER (#10371227376,
   05.10.2026).

   Målt på leverandørsida: «Dokumentasjon» og «Oppfølging» er <h2> med
   klassen .h3, og .h3 fra sand_ui setter størrelse og serif, men ingen
   vekt — altså 400, nøyaktig samme vekt som brødteksten under dem. På
   hjemsida er <h2> derimot 16,8px/700. Samme nivå, to uttrykk, og det
   svakeste av dem satt på sidenes faste inndeling.

   Torleiv valgte 05.10.2026: behold serif og 18px, gi dem vekt 600.
   Minste endring som løser det — de leses som overskrifter uten å
   konkurrere med H1 (36px/700). Hjemsidas eget uttrykk er urørt; at
   hero-sida er sans-serif er et bevisst skille mellom sidetyper, ikke
   en inkonsistens.

   Her og ikke i sand_ui/text.css, av samme grunn som .text-dense over:
   en oppdatering av designsystemet skal ikke stryke valget.

   Gjelder sju visninger — leverandørens dokumentasjon og oppfølging,
   kommentartråden når den er innfelt, versjons- og endringshistorikken,
   og tilknyttede oppgaver. */
.h3 {
    font-weight: 600;
}
