/* ============================================================================================
   mediflora-ui.css — the shared UI layer for every Mediflora page                           v8
   Loaded by admin-portal.html, customer-portal.html, mediflora-public.html and styleguide.html:
     <link rel="stylesheet" href="mediflora-ui.css?v=N" />   (AFTER fonts css, BEFORE the inline <style>)
   v2 (cross-portal review): one stepper (.recsteps; admin .rs aliases), one dl.facts (+ .strong), .tone-gold / .b-attn
   for "needs you", KPI units in the body font, tabs at 14.5px, white focus ring on .side / .mbar,
   .empty.compact, .avatar.xl (84px profile header), .kicker.muted (quiet group label).
   v3 (all opt-in, see "v3 additions" in the components layer): loading placeholders (.skel*), phone tables
   (table.mf-stack), segmented control (.seg), inbox + chat (.inbox, .inbox-row, .chat, .bubble), preview frame
   (.preview-frame, .merge-chip), calendar chips (.cal-chip, .cal-today), risk matrix (table.riskmx).
   v4: charts (.mfc*, drawn by MF.chart), print (layer mf.print, .print-doc, .sig-block, .print-only / .no-print /
   .print-keep, @page numbers), forms (44px fields on phones, a 44px .ihint target, .req, .field-error, .breadcrumbs),
   dark-theme tokens ([data-theme="dark"] / "auto"; nothing turns it on yet). The component colours that used to be
   literals are tokens now, with the same light values. The shared phone media queries are screen-only.
   v5: tabs are WAI-ARIA tabs everywhere (MF.tabs in mediflora-ui.js); the tab focus ring moved inside the tab.
   v6: date, time and month fields (mf-date, .mf-dt*, the .mf-dtp picker; .mf-dtp-mons, the month picker) drawn by
       MF.dateField in the reader's language.
   v7: the chip picker (.mf-pick, .mf-tag, drawn by MF.pick), toggle pills (.mf-togs, .mf-tog: MF.toggles) and the
       .mf-count pill — first used by «Rediger preferanser» (admin fagperson record and Min side).
   v8: the availability week grid (.mf-wk, .mf-wk-c, drawn by MF.weekGrid) and its legend (.mf-wk-legend) — wave E · T1,
       «Når kan du jobbe?» on Min side and «Tilgjengelighet» on the admin fagperson record.

   HOW THE CASCADE WORKS HERE
   Everything below sits in cascade layers. Unlayered CSS (each page's own inline <style>) ALWAYS
   beats layered CSS, whatever its specificity. So a page keeps its current look until it deletes
   its own copy of a rule; then the shared version takes over. That is the whole migration path.
   Bump ?v= in every page in the same commit as any change here (nginx caches .css for 7 days).

   DESIGN RULES (the public site is the source of truth)
   Flat and calm: no gradients, no emoji, no glow, no left-border accent stripes, no gold stripe
   before headings. Gold is a FILL with dark text on it (--on-gold); gold-coloured text on a light
   surface uses --gold-ink. Headings and numbers in Lexend, everything else in Source Sans 3.
   ============================================================================================ */
@layer mf.tokens, mf.base, mf.components, mf.print;   /* mf.print is last: on paper it wins over the components */

/* ── 1. Tokens ─────────────────────────────────────────────────────────────────────────────── */
@layer mf.tokens {
  :root {
    /* Surfaces, text, lines */
    --bg: #f1f4f9; --surface: #fff; --ink: #0f2233; --muted: #56697e; --placeholder: #66788c;
    --line: #e2e8ee; --line-soft: #eff3f8; --line-strong: #d6dde6; --line-hover: #c5cfdb;
    --chip: #eef2f6; --chip-hover: #e3e9f0;
    /* Brand */
    --brand: #45577a; --brand-dark: #313f59; --brand-soft: #edf1f7; --sidebar: #2e3c56; --accent: #3a5a98;
    --gold: #ffd460; --gold-dark: #e3b948; --gold-soft: #fff3cc; --gold-ink: #7a5b0c; --on-gold: #2a3650;
    --logo-gold: #c99a1e; --logo-tile: #283449;
    /* Semantic colours */
    --ok: #067647; --warn: #b54708; --danger: #b42318; --danger-line: #f2c4bf;
    /* Tone pairs (background + text). Every pair is at least 4.5:1; styleguide.html measures them live. */
    --ok-bg: #e7f6ee;      --ok-fg: #067647;
    --info-bg: #e7f0fe;    --info-fg: #3a5a98;
    --warn-bg: #fef1de;    --warn-fg: #a8430a;
    --danger-bg: #fdeceb;  --danger-fg: #b42318;
    --neutral-bg: #eef2f6; --neutral-fg: #475467;
    /* Type */
    --font-head: 'Lexend', 'Segoe UI', system-ui, -apple-system, sans-serif;
    --font-body: 'Source Sans 3', 'Segoe UI', system-ui, -apple-system, sans-serif;
    --fs-xs: 12.5px; --fs-sm: 13.5px; --fs-md: 15px; --fs-lg: 17px; --fs-xl: 20px; --fs-2xl: 23px; --fs-3xl: 32px;
    /* Shape and depth */
    --radius-sm: 10px; --radius: 16px; --radius-lg: 20px; --radius-photo: 28px;
    --shadow: 0 1px 2px rgba(16,35,51,.06), 0 10px 30px rgba(16,35,51,.06);
    --shadow-lg: 0 16px 38px -10px rgba(16,35,51,.20);
    /* Focus: one outline for everything, one ring for form controls */
    --focus: #3a5a98; --focus-ring: 0 0 0 3px rgba(69,87,122,.24); --focus-ring-danger: 0 0 0 3px rgba(180,35,24,.18);
    /* Stacking order */
    --z-mbar: 60; --z-scrim: 70; --z-drawer: 80; --z-boot: 200; --z-viewer: 400; --z-toast: 500;
    /* v4: colours the components used to hard-code, as tokens, so a theme can change them. Every light value below is
       exactly the colour the component had before (no visual change); the dark set is further down. */
    --on-brand: #fff; --on-danger: #fff; --on-ok: #fff;             /* text on a --brand/--brand-dark, --danger, --ok fill */
    --inverse-bg: #0f2233; --inverse-fg: #fff;                        /* toast and tooltip: the opposite of the page */
    --toast-ok: #7fd8a8; --toast-err: #ffa39a;                        /* the toast's leading icon */
    --hover-soft: #f6f8fc;                                            /* row / KPI cell hover */
    --danger-strong: #9b1d13;                                         /* solid danger button, hover */
    --empty-ico: #aab6c4; --dot-neutral: #98a5b5; --crit-bg: #f8d3ce; --rm-id-line: rgba(15,34,51,.14);
    --merge-line: #d3dcea; --merge-hover: #dfe6f1; --merge-hover-line: #b9c7dc;
    --rate-natt-bg: #e3e4fb; --rate-natt-fg: #3b3a8f; --rate-hd-bg: #fde3cf; --rate-hd-fg: #9a3412;
    --skel: #e3e9f0;                                                  /* loading shapes (= --chip-hover) */
    --backdrop: rgba(15,34,51,.45);
    --sheet-shadow: 0 1px 2px rgba(16,35,51,.06), 0 8px 24px rgba(16,35,51,.08);
    --tip-shadow: 0 8px 22px rgba(16,35,51,.24);
    /* Charts (MF.chart): one series in brand gold; a value below zero in slate; the period still running as an
       outline; hairline grid, a firmer zero line. Text stays in --ink / --muted, never in the bar colour. */
    --chart-bar: #ffd460; --chart-bar-hover: #e3b948; --chart-neg: #7a889d; --chart-neg-hover: #5f6d82;
    --chart-part-bg: #fff3cc; --chart-part-line: #e3b948; --chart-grid: #eff3f8; --chart-zero: #c5cfdb;
  }

  /* ── Dark theme (groundwork: nothing turns it on yet) ──────────────────────────────────────────
     data-theme="dark" on <html> (or on any element, for a dark island such as the styleguide preview) swaps every
     token; data-theme="auto" follows the operating system. Every text pair is at least 4.5:1 (tone text on its tone,
     ink/muted on bg/surface/chip, text on fills), focus and chart marks at least 3:1: styleguide.html measures them.
     Rules for a page that adopts it: colours only through tokens (a literal #fff / #0f2233 in a page rule will not
     follow), text on a coloured fill through the --on-* tokens, and no second copy of these values. The two blocks
     below must stay identical (the only difference is the selector). */
  [data-theme="dark"] {
    color-scheme: dark;
    --bg: #0f1723; --surface: #172230; --ink: #e6ecf3; --muted: #a2b1c4; --placeholder: #8a9bb0;
    --line: #273549; --line-soft: #1e2b3c; --line-strong: #3a4b63; --line-hover: #4d6180;
    --chip: #1f2c3d; --chip-hover: #29384c;
    --brand: #9db4e2; --brand-dark: #c2d2f0; --brand-soft: #1b2a42; --sidebar: #111a27; --accent: #a8c3f5;
    --gold: #ffd460; --gold-dark: #e3b948; --gold-soft: #3b3012; --gold-ink: #f4cf5c; --on-gold: #2a3650;
    --logo-gold: #f0c243; --logo-tile: #283449;
    --ok: #47c98a; --warn: #f5a05a; --danger: #f97a6e; --danger-line: #6b2a26;
    --ok-bg: #11301f;      --ok-fg: #7ee2ae;
    --info-bg: #172a4d;    --info-fg: #a8c3f5;
    --warn-bg: #3a2412;    --warn-fg: #fbbd84;
    --danger-bg: #3f1a18;  --danger-fg: #ffa39a;
    --neutral-bg: #243142; --neutral-fg: #c3cdd9;
    --shadow: 0 1px 2px rgba(0,0,0,.4), 0 10px 30px rgba(0,0,0,.35);
    --shadow-lg: 0 16px 38px -10px rgba(0,0,0,.65);
    --focus: #a8c3f5; --focus-ring: 0 0 0 3px rgba(157,180,226,.38); --focus-ring-danger: 0 0 0 3px rgba(249,122,110,.32);
    --on-brand: #0f1723; --on-danger: #0f1723; --on-ok: #0f1723;
    --inverse-bg: #e6ecf3; --inverse-fg: #0f1723; --toast-ok: #067647; --toast-err: #b42318;
    --hover-soft: #1c2838; --danger-strong: #ffb4ab;
    --empty-ico: #5d6f86; --dot-neutral: #7b8a9e; --crit-bg: #5a1f1b; --rm-id-line: rgba(255,255,255,.18);
    --merge-line: #34466a; --merge-hover: #22324d; --merge-hover-line: #4a5f88;
    --rate-natt-bg: #25264f; --rate-natt-fg: #c5c6f7; --rate-hd-bg: #3d2412; --rate-hd-fg: #fdba8c;
    --skel: #253346;
    --backdrop: rgba(0,0,0,.6);
    --sheet-shadow: 0 1px 2px rgba(0,0,0,.4), 0 8px 24px rgba(0,0,0,.4);
    --tip-shadow: 0 8px 22px rgba(0,0,0,.5);
    --chart-bar: #ffd460; --chart-bar-hover: #ffe28f; --chart-neg: #7d8ca3; --chart-neg-hover: #9aa8bd;
    --chart-part-bg: #3b3012; --chart-part-line: #e3b948; --chart-grid: #223044; --chart-zero: #4d6180;
  }
  @media (prefers-color-scheme: dark) {
    [data-theme="auto"] {
      color-scheme: dark;
      --bg: #0f1723; --surface: #172230; --ink: #e6ecf3; --muted: #a2b1c4; --placeholder: #8a9bb0;
      --line: #273549; --line-soft: #1e2b3c; --line-strong: #3a4b63; --line-hover: #4d6180;
      --chip: #1f2c3d; --chip-hover: #29384c;
      --brand: #9db4e2; --brand-dark: #c2d2f0; --brand-soft: #1b2a42; --sidebar: #111a27; --accent: #a8c3f5;
      --gold: #ffd460; --gold-dark: #e3b948; --gold-soft: #3b3012; --gold-ink: #f4cf5c; --on-gold: #2a3650;
      --logo-gold: #f0c243; --logo-tile: #283449;
      --ok: #47c98a; --warn: #f5a05a; --danger: #f97a6e; --danger-line: #6b2a26;
      --ok-bg: #11301f;      --ok-fg: #7ee2ae;
      --info-bg: #172a4d;    --info-fg: #a8c3f5;
      --warn-bg: #3a2412;    --warn-fg: #fbbd84;
      --danger-bg: #3f1a18;  --danger-fg: #ffa39a;
      --neutral-bg: #243142; --neutral-fg: #c3cdd9;
      --shadow: 0 1px 2px rgba(0,0,0,.4), 0 10px 30px rgba(0,0,0,.35);
      --shadow-lg: 0 16px 38px -10px rgba(0,0,0,.65);
      --focus: #a8c3f5; --focus-ring: 0 0 0 3px rgba(157,180,226,.38); --focus-ring-danger: 0 0 0 3px rgba(249,122,110,.32);
      --on-brand: #0f1723; --on-danger: #0f1723; --on-ok: #0f1723;
      --inverse-bg: #e6ecf3; --inverse-fg: #0f1723; --toast-ok: #067647; --toast-err: #b42318;
      --hover-soft: #1c2838; --danger-strong: #ffb4ab;
      --empty-ico: #5d6f86; --dot-neutral: #7b8a9e; --crit-bg: #5a1f1b; --rm-id-line: rgba(255,255,255,.18);
      --merge-line: #34466a; --merge-hover: #22324d; --merge-hover-line: #4a5f88;
      --rate-natt-bg: #25264f; --rate-natt-fg: #c5c6f7; --rate-hd-bg: #3d2412; --rate-hd-fg: #fdba8c;
      --skel: #253346;
      --backdrop: rgba(0,0,0,.6);
      --sheet-shadow: 0 1px 2px rgba(0,0,0,.4), 0 8px 24px rgba(0,0,0,.4);
      --tip-shadow: 0 8px 22px rgba(0,0,0,.5);
      --chart-bar: #ffd460; --chart-bar-hover: #ffe28f; --chart-neg: #7d8ca3; --chart-neg-hover: #9aa8bd;
      --chart-part-bg: #3b3012; --chart-part-line: #e3b948; --chart-grid: #223044; --chart-zero: #4d6180;
    }
  }
}

/* ── 2. Base: element defaults. Zero specificity (:where) so any class can override them. ── */
@layer mf.base {
  *, *::before, *::after { box-sizing: border-box; }
  :where(html) { color-scheme: light; -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
  /* A themed island (data-theme on an element below <html>) paints its own page colours; <html> gets them via body. */
  :where(:not(html)[data-theme]) { background-color: var(--bg); color: var(--ink); }
  :where(body) { margin: 0; font-family: var(--font-body); background: var(--bg); color: var(--ink);
    -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; }
  :where(h1, h2, h3, h4) { font-family: var(--font-head); }
  :where(h1, h2, h3) { text-wrap: balance; }
  /* No link ever falls back to browser blue. */
  :where(a) { color: var(--brand); text-underline-offset: 2px; }
  :where(a:hover) { color: var(--brand-dark); }
  /* Native controls otherwise render in Arial. */
  :where(button, input, select, textarea) { font-family: inherit; }

  /* Form controls: 42px tall (padding + 20px line), 1px --line-strong, 10px radius. */
  :where(input:not([type=checkbox], [type=radio], [type=range], [type=file], [type=color], [type=hidden],
         [type=submit], [type=button], [type=reset], [type=image]), select, textarea) {
    font: inherit; font-size: var(--fs-md); line-height: 20px; color: var(--ink);
    background-color: var(--surface); border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
    padding: 10px 12px; max-width: 100%; transition: border-color .15s, box-shadow .15s;
  }
  :where(select) { cursor: pointer; padding-block: 8.5px; }   /* the native menulist ignores line-height: 8.5+23+8.5+2 = 42px */
  /* Brand chevron instead of the native arrow — OPT-IN, because every portal select rule today uses the
     `background:` shorthand (which would wipe the chevron and leave no arrow at all) and its own padding.
     On: new .field markup, select.mf-select, or a whole page with class "mf-forms" on <html>/<body> once
     that page has deleted its own select rules. */
  :where(.mf-forms select, .field select, select.mf-select):where(:not([multiple], [size])) {
    appearance: none; -webkit-appearance: none; padding-block: 10px; padding-right: 36px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2356697e' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
    background-repeat: no-repeat; background-position: right 12px center; background-size: 16px 16px;
  }
  :where(textarea) { line-height: 1.5; resize: vertical; }
  /* Date/time inputs: drop Chromium's inner padding so they match the 42px text fields. */
  :where(input)::-webkit-datetime-edit, :where(input)::-webkit-datetime-edit-fields-wrapper { padding-block: 0; }
  :where(input)::-webkit-calendar-picker-indicator { margin-block: 0; padding-block: 0; }
  :where(input, textarea)::placeholder { color: var(--placeholder); opacity: 1; }
  :where(input, select, textarea):where(:hover:not(:disabled, :focus)) { border-color: var(--line-hover); }
  :where(input, select, textarea):disabled { background-color: var(--bg); color: var(--muted); cursor: not-allowed; }
  :where(input[type=checkbox], input[type=radio]) { accent-color: var(--brand); }
  :where(input, select, textarea):where([aria-invalid=true], .invalid) { border-color: var(--danger); }
  /* Phones (≤820px, the portals' phone breakpoint): 16px text, because iOS zooms into any field under 16px on focus,
     and a 44px touch target (v4; was 42px). The customer portal's dialog/filter rule and Min side's .app main rule
     already say 44px, so nothing changes there; admin fields gain 2px. A page rule that sets its own height still wins. */
  @media screen and (max-width: 820px) {
    :where(input:not([type=checkbox], [type=radio], [type=range], [type=file], [type=color], [type=hidden],
           [type=submit], [type=button], [type=reset], [type=image]), select, textarea) { font-size: 16px; min-height: 44px; }
  }
  /* The brand chevron (opt-in above) in the dark theme: a data URI cannot read a token, so the stroke is restated. */
  :where([data-theme="dark"]) :where(.mf-forms select, .field select, select.mf-select):where(:not([multiple], [size])) {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23a2b1c4' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  }
  @media (prefers-color-scheme: dark) {
    :where([data-theme="auto"]) :where(.mf-forms select, .field select, select.mf-select):where(:not([multiple], [size])) {
      background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23a2b1c4' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
    }
  }

  /* Focus: one visible outline everywhere; text-like form controls swap it for a single ring.
     Checkboxes, radios and other non-text inputs keep the outline (a native checkbox cannot show the
     border colour, and the ring alone is ~1.5:1). The ring rule uses a TRANSPARENT outline, not none:
     in forced-colours mode (Windows High Contrast) box-shadow is dropped and the outline is painted
     in the system colour, so focus stays visible there. */
  :where(:focus-visible) { outline: 3px solid var(--focus); outline-offset: 2px; }
  :where(input:not([type=checkbox], [type=radio], [type=range], [type=file], [type=color]), select, textarea):focus {
    outline: 2px solid transparent; outline-offset: 0; border-color: var(--brand); box-shadow: var(--focus-ring); }
  :where(input, select, textarea):where([aria-invalid=true], .invalid):focus { border-color: var(--danger); box-shadow: var(--focus-ring-danger); }
  /* Dark surfaces (the portal sidebars .side and phone bars .mbar count as dark): --focus is ~1.6:1 there, so the
     ring turns white. A white popup that opens inside one (the language list, admin's user popover .upop, or
     anything marked .on-light) gets the normal ring back. */
  :where(.on-dark, .side, .mbar) :focus-visible { outline-color: #fff; }
  :where(.on-dark, .side, .mbar) :where(.on-light, .langlist, .upop) :focus-visible { outline-color: var(--focus); }

  /* Tables: sentence-case muted headers without fill, hairline rows, no zebra, tabular numbers. */
  :where(table) { width: 100%; border-collapse: collapse; font-size: 14px; font-variant-numeric: tabular-nums; }
  :where(th) { padding: 10px 12px; border-bottom: 1px solid var(--line); text-align: left; vertical-align: bottom;
    font-size: var(--fs-xs); font-weight: 600; color: var(--muted); text-transform: none; letter-spacing: 0; background: none; }
  :where(td) { padding: 12px; border-bottom: 1px solid var(--line-soft); }
  :where(tr:last-child > td) { border-bottom: 0; }
  :where(tr.click) { cursor: pointer; transition: background-color .12s; }
  :where(tr.click:hover) { background: var(--chip); }

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

/* ── 3. Components (class names the portals already use; aliases noted) ─────────────────── */
@layer mf.components {

  /* Buttons. Default (no variant) = quiet secondary on --chip. Variants: primary, gold, ghost, danger (+ .solid).
     Sizes: sm 32px, default 40px, lg 48px. Works the same on <button> and <a>. */
  .btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px; min-height: 40px;
    padding: 9px 16px; border: 1px solid transparent; border-radius: var(--radius-sm); background: var(--chip);
    color: var(--ink); font: inherit; font-size: 14px; font-weight: 700; line-height: 1.2; text-align: center;
    text-decoration: none; cursor: pointer; -webkit-tap-highlight-color: transparent;
    transition: background-color .15s, border-color .15s, color .15s, transform .12s; }
  .btn:not(:disabled):hover { background: var(--chip-hover); color: var(--ink); }
  .btn:not(:disabled):active { transform: translateY(1px); }
  .btn svg { width: 18px; height: 18px; flex-shrink: 0; }
  .btn.primary { background: var(--brand); color: var(--on-brand); }
  .btn.primary:not(:disabled):hover { background: var(--brand-dark); color: var(--on-brand); }
  .btn.gold { background: var(--gold); color: var(--on-gold); }
  .btn.gold:not(:disabled):hover { background: var(--gold-dark); color: var(--on-gold); }
  .btn.ghost { background: var(--surface); border-color: var(--line-strong); color: var(--ink); }
  .btn.ghost:not(:disabled):hover { background: var(--chip); border-color: var(--line-hover); color: var(--ink); }
  .btn.danger { background: var(--surface); border-color: var(--danger-line); color: var(--danger); }
  .btn.danger:not(:disabled):hover { background: var(--danger-bg); color: var(--danger); }
  .btn.danger.solid { background: var(--danger); border-color: var(--danger); color: var(--on-danger); }
  .btn.danger.solid:not(:disabled):hover { background: var(--danger-strong); border-color: var(--danger-strong); color: var(--on-danger); }
  .btn.sm { min-height: 32px; padding: 5px 12px; gap: 6px; border-radius: 9px; font-size: 13px; }
  .btn.sm svg { width: 16px; height: 16px; }
  .btn.lg { min-height: 48px; padding: 12px 22px; border-radius: 12px; font-size: 15px; }
  .btn.block { display: flex; width: 100%; }
  .btn.icon-only { width: 40px; padding: 0; }
  .btn.sm.icon-only { width: 32px; }
  .btn.lg.icon-only { width: 48px; }
  .btn:disabled, .btn[aria-disabled=true] { opacity: .5; cursor: not-allowed; }
  a.btn[aria-disabled=true] { pointer-events: none; }
  .btn .bspin { display: inline-block; width: 14px; height: 14px; border: 2px solid currentColor;
    border-right-color: transparent; border-radius: 50%; animation: mf-spin .6s linear infinite; }
  @keyframes mf-spin { to { transform: rotate(360deg); } }

  /* Text button / inline link action */
  .lnk { padding: 0; border: 0; background: none; font: inherit; color: var(--brand); cursor: pointer;
    text-decoration: none; text-underline-offset: 2px; }
  .lnk:hover { color: var(--brand-dark); text-decoration: underline; }
  .lnk.del { color: var(--danger); }
  .lnk:disabled { opacity: .5; cursor: not-allowed; text-decoration: none; }

  /* Fields. New markup: .field > label + control + .help/.error.
     Aliases kept so current markup works: admin .flab, customer .fld > span (+ .fld-cb), public .pf-row (+ .pf-chk). */
  .fields, .pf { display: grid; gap: 14px; }
  .field, .fld { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
  .fld { margin-bottom: 14px; }   /* customer cform stacks .fld labels without a grid */
  .field-row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
  .field > label, .field-label, .flab, .fld > span { display: block; margin: 0; font-size: var(--fs-sm);
    font-weight: 600; line-height: 1.35; color: var(--ink); }
  .flab { margin-bottom: 6px; }
  .pf-row { display: grid; gap: 6px; font-size: var(--fs-sm); font-weight: 600; color: var(--ink); }
  .pf-row :is(input, select, textarea) { font-weight: 400; }
  :is(.field, .fld, .pf-row, dialog) :is(input:not([type=checkbox], [type=radio], [type=range], [type=file]), select, textarea) { width: 100%; }
  .field textarea { min-height: 96px; }
  .field .help, .field-help { margin: 0; font-size: var(--fs-xs); line-height: 1.45; color: var(--muted); }
  .field .error, .field-error, .ferr { margin: 0; font-size: var(--fs-xs); line-height: 1.45; font-weight: 600; color: var(--danger); }
  .field-check, .fld-cb, .pf-chk { display: flex; flex-direction: row; align-items: center; gap: 8px; font-size: 14.5px; font-weight: 400; }
  .fld.fld-cb > span { font-size: 14.5px; font-weight: 400; }   /* the .fld > span field-label alias must not bold a checkbox text */
  .field-check input, .fld-cb input, .pf-chk input { width: auto; margin: 0; }
  .filterbar { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-bottom: 16px; }
  @media screen and (max-width: 560px) { .field-row { grid-template-columns: minmax(0, 1fr); } }

  /* Dialog: 20px radius, 24px padding, dimmed + softly blurred backdrop, Lexend title WITHOUT a stripe.
     Save = .btn.primary, cancel = .btn.ghost, right-aligned in .dlg-actions (alias .pf-actions). */
  dialog { border: 0; border-radius: var(--radius-lg); padding: 24px; background: var(--surface); color: var(--ink);
    box-shadow: var(--shadow-lg); width: min(480px, calc(100vw - 32px)); max-width: calc(100vw - 32px); }
  dialog::backdrop { background: var(--backdrop); backdrop-filter: blur(2px); }
  dialog h3, .dlg-title { margin: 0 0 16px; font: 700 18px/1.3 var(--font-head); color: var(--ink); }
  .dlg-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; margin-bottom: 16px; }
  .dlg-head :is(h2, h3, .dlg-title) { margin: 0; min-width: 0; overflow-wrap: anywhere; }   /* «Melding til … (a@b.invalid)» wraps; the × stays */
  .dlg-head p { margin: 4px 0 0; font-size: 14px; color: var(--muted); }
  .dlg-x { flex-shrink: 0; display: grid; place-items: center; width: 36px; height: 36px; margin: -6px -8px 0 0;
    border: 0; border-radius: var(--radius-sm); background: none; color: var(--muted); cursor: pointer; }
  .dlg-x:hover { background: var(--chip); color: var(--ink); }
  .dlg-x svg { width: 20px; height: 20px; }
  .dlg-actions, .pf-actions { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 10px; margin-top: 20px; }

  /* Panel (card). The h2 is plain: no ::before stripe, no rule under it. */
  .panel { margin-bottom: 18px; padding: 20px; background: var(--surface); border: 1px solid var(--line);
    border-radius: var(--radius); box-shadow: var(--shadow); }
  .panel h2 { margin: 0 0 14px; font: 700 17px/1.3 var(--font-head); color: var(--ink); }
  .panel-head, .panelhead { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
    gap: 8px 12px; margin-bottom: 14px; }
  .panel-head h2, .panelhead h2 { margin: 0; }
  .panel-head p, .panelhead p { margin: 2px 0 0; font-size: var(--fs-sm); color: var(--muted); }

  /* Table helpers (element styles are in mf.base) */
  .table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  :is(td, th).num { text-align: right; white-space: nowrap; }
  th.sortable { cursor: pointer; user-select: none; }
  th[aria-sort] { white-space: nowrap; }
  th.sortable:hover { color: var(--ink); }
  th[aria-sort=ascending]::after, th[aria-sort=descending]::after { content: ""; display: inline-block; width: 12px;
    height: 12px; margin-left: 4px; vertical-align: -1px; background: currentColor;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E") center / contain no-repeat;
            mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E") center / contain no-repeat; }
  th[aria-sort=ascending]::after { transform: rotate(180deg); }

  /* Record facts: label / value rows with hairline rules (oppdrag, avtale, faktura, fagperson, lead, job aside, profile).
     Labels 14px muted, values 15px regular; .strong makes the values semibold where a list is a summary (job aside).
     The label column is 180px, and shrinks with the list itself (38% of its width, never under 96px) in a narrow card
     or on a phone, so no container query or breakpoint is needed.
     Context tweaks stay in the page: column widths (.amounts, .tl-body, .inv-sum), right-aligned sums, .tot rows. */
  dl.facts { display: grid; grid-template-columns: minmax(96px, min(180px, 38%)) minmax(0, 1fr); align-content: start; margin: 0; }
  dl.facts > dt, dl.facts > dd { margin: 0; padding: 11px 0; border-top: 1px solid var(--line-soft); }
  dl.facts > dt:first-of-type, dl.facts > dt:first-of-type + dd { border-top: 0; }
  dl.facts > dt { padding-right: 16px; font-size: 14px; color: var(--muted); }
  dl.facts > dd { min-width: 0; font-size: 15px; font-weight: 400; color: var(--ink); overflow-wrap: anywhere; }
  dl.facts.strong > dd { font-weight: 600; }

  /* Badges. Five tones; an unmapped status falls back to neutral so it never renders as bare text.
     Every b-<status> class used by the three portals is mapped here (see styleguide.html for the table). */
  .badge { display: inline-flex; align-items: center; gap: 5px; padding: 3px 10px; border-radius: 999px;
    font-size: var(--fs-xs); font-weight: 700; line-height: 1.35; white-space: nowrap;
    background: var(--neutral-bg); color: var(--neutral-fg); }
  .badge svg { width: 13px; height: 13px; flex-shrink: 0; }
  /* The status -> tone map sits near the end of this layer (see "Tones") so .tone-* also tints tiles and chips. */

  /* Chip: neutral tag; as a <button> it is a filter toggle (.on / aria-pressed) */
  .chip { display: inline-flex; align-items: center; gap: 6px; padding: 3px 11px; border-radius: 999px;
    background: var(--chip); color: var(--ink); font-size: var(--fs-xs); font-weight: 600; line-height: 1.35; }
  .chip svg { width: 14px; height: 14px; flex-shrink: 0; color: var(--brand); }
  button.chip { min-height: 32px; padding: 5px 12px; border: 0; font-family: inherit; cursor: pointer; }
  button.chip:hover { background: var(--chip-hover); }
  .chip.on, .chip[aria-pressed=true] { background: var(--brand-dark); color: var(--on-brand); }
  .chip.on svg, .chip[aria-pressed=true] svg { color: inherit; }

  /* Kicker: small uppercase label above a heading */
  .kicker { font-size: var(--fs-xs); font-weight: 700; letter-spacing: 1px; text-transform: uppercase; color: var(--gold-ink); }
  .on-dark .kicker { color: var(--gold); }
  /* Quiet group label (PERSON / STATUS over record fact groups, a label inside an inset box): same type, muted.
     The gold-ink kicker stays the label over a page or card heading. */
  .kicker.muted { color: var(--muted); }
  .on-dark .kicker.muted { color: #9fb0c6; }

  /* Tabs (alias .ptabs used on Min side). Active = .on or aria-selected; counts hide when empty.
     One explicit size (not the body size it would inherit), so list tabs, record tabs and Min side tabs match. */
  .tabs, .ptabs { display: flex; flex-wrap: wrap; gap: 2px; margin: 2px 0 16px; border-bottom: 1px solid var(--line); }
  .tab, .ptabs button { display: inline-flex; align-items: center; gap: 7px; margin-bottom: -1px; padding: 10px 14px;
    border: 0; border-bottom: 2px solid transparent; background: none; font: inherit; font-size: 14.5px; font-weight: 600;
    color: var(--muted); cursor: pointer; }
  .tab:hover, .ptabs button:hover { color: var(--ink); }
  .tab.on, .tab[aria-selected=true], .ptabs button.active, .ptabs button[aria-selected=true] { color: var(--ink); border-bottom-color: var(--gold-dark); }
  .tabn { padding: 1px 8px; border-radius: 999px; background: var(--chip); color: var(--muted); font-size: 11.5px;
    font-weight: 700; font-variant-numeric: tabular-nums; }
  .tabn:empty { display: none; }
  .tab.on .tabn, .tab[aria-selected=true] .tabn { background: var(--gold-soft); color: var(--gold-ink); }
  /* The focus ring sits inside the tab: a row that scrolls sideways (record tabs, status tabs on phones) would clip a
     ring drawn outside it. MF.tabs (mediflora-ui.js) gives the row the ARIA tabs pattern + arrow keys. */
  .tabs .tab:focus-visible, .ptabs button:focus-visible, [role="tablist"] > [role="tab"]:focus-visible { outline-offset: -3px; }

  /* KPI strip: one ruled card, cells separated by 1px hairlines (the gaps over --line). --n = cells per row.
     Each CELL (li) is the size container: the numeral and the side padding follow the width of the cell itself, not
     of the strip — sized from the strip, a 28px «kr 13 692» overran a quarter of a 560–1000px strip into the next
     cell (review 2026-10-01, MOB-2). 13.5cqi fits «kr 113 692» (5em in Lexend 600) in any cell of 110px or more,
     and «kr 1 113 692» (5.85em) in one of 170px or more. */
  .kstrip { container-type: inline-size; list-style: none; margin: 0; padding: 0; display: grid;
    grid-template-columns: repeat(var(--n, 4), minmax(0, 1fr)); gap: 1px; background: var(--line);
    border: 1px solid var(--line); border-radius: var(--radius-lg); overflow: hidden; }
  .kstrip > li { display: flex; min-width: 0; background: var(--surface); container-type: inline-size; }
  .kcell { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; padding: 18px;
    padding-inline: clamp(12px, 12.8cqi, 18px); border: 0; border-radius: 0; background: var(--surface);
    font: inherit; color: var(--ink); text-align: left; }
  button.kcell { cursor: pointer; transition: background-color .14s; }
  button.kcell:hover { background: var(--hover-soft); }
  button.kcell:focus-visible { outline-offset: -3px; }
  .kn { display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 3px; font-family: var(--font-head);
    font-size: 28px; font-size: clamp(16px, 13.5cqi, 28px); font-weight: 600; line-height: 1.15;
    font-variant-numeric: tabular-nums; white-space: nowrap; color: var(--ink); }
  /* Unit ("t", "kr", "mill", "%") in the body font: Lexend's small lowercase t reads as a dagger at these sizes.
     Never under 12.5px, so a unit next to the 20px phone numeral stays legible. */
  .kn small { margin-left: 3px; font-family: var(--font-body); font-size: max(var(--fs-xs), .54em); font-weight: 600; color: var(--muted); }
  .kl { font-size: 14px; line-height: 1.3; color: var(--muted); }
  .ksub { margin-top: 6px; font-size: 13px; color: var(--muted); }
  @media screen and (max-width: 560px) {
    .kstrip { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .kstrip > li:last-child:nth-child(odd) { grid-column: span 2; }
    .kstrip > li:last-child:nth-child(odd) .kn { font-size: clamp(16px, 6.75cqi, 28px); }   /* two cells wide: the same size */
    .kcell { padding: 16px; }
  }

  /* Stepper: "where is this process?" — the same look in all three portals (customer candidates and order wizard,
     Min side applications, admin pipelines). Numbered 28px dots on a 2px connector. States on the li:
       todo (none) = hollow dot + number · .done = soft gold + check · .cur = solid gold + number, bold label
       (+ aria-current="step") · .won / .lost = terminal (ok / danger fill) · .paused = current step on hold (dashed).
     The connector INTO a step turns gold once that step is reached. Full width of its card (no max-width).
     Markup: ol.recsteps > li.recstep > span.dot + span.lbl; a step you can go back to wraps them in button.recstep-go.
     Admin aliases for recSteps() markup (li.rs > .rs-step > .rs-dot + .rs-lbl): dot and label states only — the
     admin keeps its own sideways-scrolling strip, button padding and connector geometry. */
  .recsteps { display: flex; align-items: flex-start; margin: 0; padding: 0; list-style: none; }
  .recstep { position: relative; flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; align-items: center;
    gap: 6px; text-align: center; }
  .recstep + .recstep::before { content: ""; position: absolute; top: 13px; left: calc(-50% + 16px); right: calc(50% + 16px);
    height: 2px; background: var(--line-strong); }
  .recstep + .recstep:is(.done, .cur, .won, .lost)::before { background: var(--gold-dark); }
  .recstep .dot, .rs-dot { position: relative; z-index: 1; flex-shrink: 0; display: grid; place-items: center; width: 28px;
    height: 28px; border: 2px solid var(--line-strong); border-radius: 50%; background: var(--surface); color: var(--muted);
    font: 600 13px/1 var(--font-head); font-variant-numeric: tabular-nums; }
  .recstep .dot svg, .rs-dot svg { width: 14px; height: 14px; }
  :is(.recstep, .rs).done :is(.dot, .rs-dot) { background: var(--gold-soft); border-color: var(--gold-dark); color: var(--gold-ink); }
  :is(.recstep, .rs).cur :is(.dot, .rs-dot) { background: var(--gold); border-color: var(--gold); color: var(--on-gold); }
  :is(.recstep, .rs).won :is(.dot, .rs-dot) { background: var(--ok); border-color: var(--ok); color: var(--on-ok); }
  :is(.recstep, .rs).lost :is(.dot, .rs-dot) { background: var(--danger); border-color: var(--danger); color: var(--on-danger); }
  :is(.recstep, .rs).paused :is(.dot, .rs-dot) { background: var(--surface); border-style: dashed; border-color: var(--muted); color: var(--muted); }
  .recstep .lbl { padding: 0 2px; overflow-wrap: anywhere; }
  .recstep .lbl, .rs-lbl { font-size: var(--fs-xs); line-height: 1.3; color: var(--muted); }
  :is(.recstep, .rs):is(.cur, .won, .lost) :is(.lbl, .rs-lbl) { color: var(--ink); font-weight: 700; }
  :is(.recstep, .rs).paused :is(.lbl, .rs-lbl) { color: var(--muted); }
  .recstep-go { display: flex; flex-direction: column; align-items: center; gap: 6px; min-height: 44px; padding: 0 4px 2px;
    border: 0; border-radius: 8px; background: none; font: inherit; color: inherit; cursor: pointer; }
  .recstep-go:not(:disabled):hover .lbl { color: var(--ink); text-decoration: underline; text-underline-offset: 2px; }
  .recstep-go:disabled { cursor: default; }
  /* Phones: five steps share ~360px, so labels drop a size and only break between words. */
  @media screen and (max-width: 640px) { .recstep .lbl { font-size: 11.5px; overflow-wrap: normal; } }

  /* Empty state. New markup: .empty > .empty-ic (icon tile) + h4 + p + optional .btn.
     A bare svg as first child (the portals' EMPTY_IC today) keeps its current look. */
  .empty { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px;
    padding: 46px 22px; text-align: center; }
  .empty > svg { width: 40px; height: 40px; color: var(--empty-ico); stroke-width: 1.5; }
  .empty-ic { display: grid; place-items: center; width: 56px; height: 56px; margin-bottom: 4px;
    border-radius: var(--radius); background: var(--chip); color: var(--brand); }
  .empty-ic svg { width: 26px; height: 26px; }
  .empty h4 { margin: 0; font: 600 16px/1.3 var(--font-head); color: var(--ink); }
  .empty p { margin: 0; max-width: 360px; font-size: 14px; line-height: 1.5; color: var(--muted); }
  .empty .btn { margin-top: 8px; }
  /* Compact: an empty SECTION inside a card (a profile tab, a document list), usually tile + one line, no h4. */
  .empty.compact { padding: 26px 16px; }

  /* Toast: above drawer, scrim and bars. Optional leading icon: .ok / .err tint it (no coloured border). */
  .toast { position: fixed; left: 50%; bottom: 22px; z-index: var(--z-toast); transform: translateX(-50%);
    display: flex; align-items: center; gap: 10px; max-width: calc(100vw - 32px); padding: 12px 18px;
    border-radius: 12px; background: var(--inverse-bg); color: var(--inverse-fg); font-size: 14.5px; line-height: 1.4;
    box-shadow: var(--shadow-lg); opacity: 0; pointer-events: none; transition: opacity .25s; }
  .toast.show { opacity: 1; pointer-events: auto; }
  .toast svg { width: 18px; height: 18px; flex-shrink: 0; }
  .toast.ok svg { color: var(--toast-ok); }
  .toast.err svg { color: var(--toast-err); }

  /* Avatar: flat initials (or a photo). Sizes sm 32 (lists, chat) / default 40 (queues, conversations) /
     lg 64 (record headers) / xl 84 (the person's own profile header; 64 on phones).
     Navy = the signed-in user and record headers; .soft = other people in lists. */
  .avatar { display: inline-grid; place-items: center; flex-shrink: 0; width: 40px; height: 40px; overflow: hidden;
    border-radius: 50%; background: var(--brand); color: var(--on-brand); font: 600 15px/1 var(--font-head); }
  .avatar img { width: 100%; height: 100%; object-fit: cover; }
  .avatar.sm { width: 32px; height: 32px; font-size: 13px; }
  .avatar.lg { width: 64px; height: 64px; font-size: 22px; }
  .avatar.xl { width: 84px; height: 84px; font-size: 30px; }
  @media screen and (max-width: 640px) { .avatar.xl { width: 64px; height: 64px; font-size: 22px; } }
  .avatar.soft { background: var(--chip); color: var(--brand-dark); }
  .avatar.gold { background: var(--gold); color: var(--on-gold); }

  /* Brand lockup: flower mark + "Medi" "flora" in Lexend, sentence case. On dark surfaces add .on-dark
     (the portal sidebars .side / .mbar count as dark). Markup comes from MF.logo() in mediflora-ui.js. */
  .mf-logo { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; }
  .lockup { display: inline-flex; align-items: center; gap: 10px; color: inherit; text-decoration: none; }
  .lockup svg, .lockup img { display: block; flex-shrink: 0; }
  .wm { font-family: var(--font-head); font-size: 18px; font-weight: 700; line-height: 1; letter-spacing: -.2px;
    color: var(--brand-dark); white-space: nowrap; }
  .wm b { font-weight: inherit; color: var(--logo-gold); }
  .lockup-tag { font-size: var(--fs-xs); font-weight: 600; color: var(--muted); white-space: nowrap; }
  :is(.on-dark, .side, .mbar) .wm { color: #fff; }
  :is(.on-dark, .side, .mbar) .wm b { color: var(--gold); }
  :is(.on-dark, .side, .mbar) .lockup-tag { color: #9fb0c6; }

  /* Icons from MF.ico() and the tile they sit in (timelines, action feeds, empty states) */
  .mf-ico { flex-shrink: 0; vertical-align: -.2em; }
  .ic-tile { display: inline-grid; place-items: center; flex-shrink: 0; width: 40px; height: 40px;
    border-radius: 12px; background: var(--chip); color: var(--brand); }
  .ic-tile svg { width: 20px; height: 20px; }
  .ic-tile.sm { width: 28px; height: 28px; border-radius: 9px; }
  .ic-tile.sm svg { width: 16px; height: 16px; }
  .ic-tile.lg { width: 56px; height: 56px; border-radius: var(--radius); }
  .ic-tile.lg svg { width: 26px; height: 26px; }

  /* Info hint (?) and its tooltip — identical in all three portals today */
  .ihint { position: relative; display: inline-flex; align-items: center; justify-content: center; width: 15px;
    height: 15px; margin-left: 5px; padding: 0; vertical-align: middle; border: 1px solid var(--line);
    border-radius: 50%; background: var(--chip); color: var(--muted);
    font: italic 700 10px/1 Georgia, 'Times New Roman', serif; cursor: help; }
  .ihint:hover, .ihint:focus-visible { background: var(--brand); border-color: var(--brand); color: var(--on-brand); }
  .ihint:focus-visible { outline: 2px solid transparent; outline-offset: 1px; }   /* the fill is the indicator; the transparent outline shows in forced colours */
  .ihint-tip { position: fixed; z-index: 2147483000; display: none; width: max-content; max-width: min(280px, calc(100vw - 24px));
    padding: 8px 10px; border-radius: 8px; background: var(--inverse-bg); color: var(--inverse-fg); font: 400 12px/1.45 var(--font-body);
    text-align: left; white-space: normal; box-shadow: var(--tip-shadow); pointer-events: none; }

  /* ══ v4 additions (all opt-in or phone-only; see the header) ═══════════════════════════════════════════ */

  /* Help tip on phones: the 15px circle keeps its size, its TOUCH target grows to 44 × 44px (a transparent ::after).
     The ::after is placed inside the circle's 1px border, so its insets count from the 13px inner box, not from the
     15px circle: calc(50% - 22px) puts each edge 22px from the centre (= -15.5px), whatever the border.
     In a field label there is only ~6px between the label and its field and ~14px up to the field before, so a label
     that holds a tip gets 5px more room above and below, and the target sits higher: 25.5px above the centre and
     18.5px below it (still 44px), so it ends just above the field instead of covering its top edge. Measured at 390px
     in the styleguide and all three portals: at least 0.8px clear of the field below and 1px of the one above.
     (A page's own unlayered ::after rule — admin's phone rule, Min side's .auth rules — still wins until it goes.) */
  @media screen and (max-width: 820px) {
    .ihint::after { content: ""; position: absolute; inset: calc(50% - 22px); }
    :is(.field > label, .field-label, .flab, .fld > span, .pf-row > span, .aflbl):has(> .ihint) { padding-block: 5px; }
    :is(.field > label, .field-label, .flab, .fld > span, .pf-row > span, .aflbl) > .ihint::after {
      inset: calc(50% - 25.5px) calc(50% - 22px) calc(50% - 18.5px); }
  }

  /* Required fields. The asterisk is decoration for sighted users; the field itself says it (required or
     aria-required="true"), so screen readers hear "påkrevd" once, not "stjerne". Plain, in the label's colour — the
     product decision in all three portals (Min side's own .req is the same rule). A space before it, as Min side
     writes it. One .req-note per form explains it when a form mixes required and optional fields:
       <label for="k-navn">Navn <span class="req" aria-hidden="true">*</span></label><input id="k-navn" required>
       <p class="req-note"><span aria-hidden="true">*</span> Må fylles ut</p> */
  .req { color: inherit; font-weight: inherit; }
  .req-note { margin: 0 0 12px; font-size: var(--fs-xs); color: var(--muted); }

  /* Inline field error: an icon and ONE text span (a flex row, so the text needs its own element), under the field
     and after its help text. The field points at it: aria-invalid="true" aria-describedby="<help-id> <error-id>".
     It is not a live region; on submit, move focus to the first invalid field (and, for long forms, show one
     summary with role="alert" above the buttons). An emptied .field-error takes no space.
       <p class="field-error" id="k-org-err">MF.ico('alert', 14)<span>Org.nr må ha 9 siffer.</span></p> */
  .field-error { display: flex; align-items: flex-start; gap: 6px; }
  .field-error > svg { width: 14px; height: 14px; margin-top: 2px; flex-shrink: 0; }
  .field-error:empty { display: none; }

  /* Breadcrumbs. Each step is a real link (<a href>) or a <button> — both look like quiet muted links — and the last
     step is the current page (a span with aria-current="page", never a link). The separator is drawn by CSS, so
     screen readers read only the steps. On phones each step is a 44px target.
       <nav class="breadcrumbs" aria-label="Brødsmulesti"><ol>
         <li><a href="#/crm">CRM</a></li><li><button type="button" data-go="customers">Kunder</button></li>
         <li><span aria-current="page">Oslo kommune</span></li></ol></nav> */
  .breadcrumbs ol { display: flex; flex-wrap: wrap; align-items: center; row-gap: 2px; margin: 0; padding: 0; list-style: none;
    font-size: var(--fs-sm); line-height: 1.35; color: var(--muted); }
  .breadcrumbs li { display: inline-flex; align-items: center; min-width: 0; }
  .breadcrumbs li + li::before { content: ""; flex-shrink: 0; width: 14px; height: 14px; margin: 0 6px; background: var(--line-hover);
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m9 6 6 6-6 6'/%3E%3C/svg%3E") center / contain no-repeat;
            mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m9 6 6 6-6 6'/%3E%3C/svg%3E") center / contain no-repeat; }
  .breadcrumbs :is(a, button) { display: inline-flex; align-items: center; min-height: 28px; margin: 0 -4px; padding: 2px 4px;
    border: 0; border-radius: 6px; background: none; font: inherit; color: var(--muted); text-align: left;
    text-decoration: none; cursor: pointer; overflow-wrap: anywhere; }
  .breadcrumbs :is(a, button):hover { color: var(--brand); text-decoration: underline; text-underline-offset: 2px; }
  .breadcrumbs :is(a, button):focus-visible { outline-offset: 0; }
  .breadcrumbs [aria-current] { font-weight: 600; color: var(--ink); overflow-wrap: anywhere; }
  @media screen and (max-width: 820px) { .breadcrumbs :is(a, button) { min-height: 44px; } }

  /* Charts: MF.chart(el, spec) in mediflora-ui.js draws these (see its header for the spec). Two forms:
       .mfc-col  columns over time (months, years): one series, a zero line, rounded ticks OR a value on every bar
                 (never both), the running period as an outline, negative values below the zero line
       .mfc-hbar horizontal bars for rankings (per department, per category): the label never truncates (it wraps,
                 and goes above the bar in a narrow card), the value at the bar's tip
     Plain HTML, not SVG: the text keeps its real size at any width. Colours come from the --chart-* tokens, the
     text from --ink / --muted. Everything a bar shows is also text: a screen-reader line in every bar, a tooltip on
     hover and keyboard focus (arrow keys walk the bars), and "Vis som tabell". */
  .mfc { position: relative; min-width: 0; container-type: inline-size; --mfc-h: 220px; }
  @container (max-width: 480px) { .mfc-plot { --mfc-h: 180px; } }
  .mfc.is-busy .mfc-frame { opacity: .45; transition: opacity .2s; }   /* reloading: keep the last picture, dimmed */
  .mfc-frame[hidden], .mfc-table[hidden] { display: none; }
  .mfc-plot { position: relative; height: var(--mfc-h); margin-left: var(--mfc-yw, 0px); }
  .mfc-area { position: absolute; inset: var(--mfc-pt, 24px) 0 var(--mfc-pb, 0px); }
  .mfc-grid { position: absolute; inset: 0; pointer-events: none; }
  .mfc-tick { position: absolute; left: 0; right: 0; bottom: calc(var(--p) * 100%); height: 0; border-top: 1px solid var(--chart-grid); }
  .mfc-tick.zero { border-top-color: var(--chart-zero); z-index: 1; }
  .mfc-tl { position: absolute; right: calc(100% + 10px); bottom: -9px; font-size: var(--fs-xs); line-height: 18px; color: var(--muted);
    white-space: nowrap; font-variant-numeric: tabular-nums; }
  .mfc.all-values .mfc-tick:not(.zero), .mfc.all-values .mfc-tl { display: none; }   /* every bar has its value: no axis */
  .mfc-bars { position: absolute; inset: 0; display: flex; margin: 0; padding: 0 4px; list-style: none; }
  .mfc-slot { position: relative; flex: 1 1 0; min-width: 0; border-radius: 6px; cursor: default; outline-offset: -2px; }
  .mfc-slot:hover, .mfc-slot.is-on { background: color-mix(in srgb, var(--brand) 6%, transparent); }
  .mfc-bar { position: absolute; left: 50%; width: min(var(--mfc-bw, 32px), calc(100% - 6px)); transform: translateX(-50%);
    bottom: calc(var(--lo) * 100%); height: calc((var(--hi) - var(--lo)) * 100%); min-height: 2px;
    border-radius: 4px 4px 0 0; background: var(--chart-bar); transform-origin: 50% 100%; transition: background-color .12s; }
  .mfc-slot.neg .mfc-bar { bottom: auto; top: calc((1 - var(--hi)) * 100%); border-radius: 0 0 4px 4px; background: var(--chart-neg);
    transform-origin: 50% 0; }
  .mfc-slot.zero .mfc-bar { display: none; }
  .mfc-slot.part .mfc-bar { background: var(--chart-part-bg); box-shadow: inset 0 0 0 1.5px var(--chart-part-line); }
  .mfc-slot:is(:hover, .is-on) .mfc-bar { background: var(--chart-bar-hover); }
  .mfc-slot.neg:is(:hover, .is-on) .mfc-bar { background: var(--chart-neg-hover); }
  .mfc-slot.part:is(:hover, .is-on) .mfc-bar { background: var(--chart-part-bg); box-shadow: inset 0 0 0 2.5px var(--chart-bar-hover); }
  .mfc-val { position: absolute; left: 50%; bottom: calc(var(--hi) * 100% + 5px); transform: translateX(-50%); visibility: hidden;
    font: 600 var(--fs-xs)/1.2 var(--font-head); color: var(--ink); white-space: nowrap; font-variant-numeric: tabular-nums; pointer-events: none; }
  .mfc-slot.neg .mfc-val { bottom: auto; top: calc((1 - var(--lo)) * 100% + 5px); }
  /* With an axis, a surface-coloured backing keeps the gridlines out of the digits. */
  .mfc:not(.all-values) .mfc-val { padding: 0 3px; border-radius: 4px; background: var(--surface); }
  .mfc-slot.zero .mfc-val { color: var(--muted); font-weight: 500; }
  .mfc-val.show { visibility: visible; }
  .mfc-val.at-start { left: 0; transform: none; }     /* first / last bar: a label wider than its column stays inside */
  .mfc-val.at-end { left: auto; right: 0; transform: none; }
  .mfc-x { display: flex; margin: 8px 0 0 var(--mfc-yw, 0px); padding: 0 4px; }
  .mfc-xl { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 1px;
    font-size: var(--fs-xs); line-height: 1.3; color: var(--muted); white-space: nowrap; }
  .mfc-xl.at-start { align-items: flex-start; }
  .mfc-xl.at-end { align-items: flex-end; }
  .mfc-xl.off > * { visibility: hidden; }             /* thinned out: every 2nd / 3rd … label, always the last one */
  .mfc-xl.part > span { font-weight: 700; color: var(--ink); }
  .mfc-grp { font-size: 11.5px; color: var(--muted); font-variant-numeric: tabular-nums; }
  .mfc-grp:empty { display: none; }
  .mfc-tip { position: absolute; z-index: 5; display: flex; flex-direction: column; gap: 1px; padding: 7px 10px; border-radius: 8px;
    background: var(--inverse-bg); color: var(--inverse-fg); box-shadow: var(--tip-shadow); white-space: nowrap; pointer-events: none;
    transform: translate(-50%, calc(-100% - 8px)); }
  .mfc-tip[hidden] { display: none; }
  .mfc-tip.below { transform: translate(-50%, 8px); }
  .mfc-tip b { font: 600 14px/1.25 var(--font-head); font-variant-numeric: tabular-nums; }
  .mfc-tip span { font-size: var(--fs-xs); line-height: 1.3; opacity: .82; }
  .mfc.is-new .mfc-bar { animation: mfc-grow .42s cubic-bezier(.2, .7, .2, 1) both; }
  @keyframes mfc-grow { from { scale: 1 0; } }
  @media (prefers-reduced-motion: reduce) { .mfc.is-new .mfc-bar { animation: none; } .mfc-bar { transition: none; } }
  .mfc-foot { display: flex; justify-content: flex-end; margin-top: 10px; }
  .mfc-switch { display: inline-flex; align-items: center; gap: 6px; min-height: 32px; padding: 4px 8px; margin-right: -8px; border: 0;
    border-radius: 8px; background: none; font: inherit; font-size: 13px; font-weight: 600; color: var(--brand); cursor: pointer; }
  .mfc-switch:hover { color: var(--brand-dark); text-decoration: underline; text-underline-offset: 2px; }
  .mfc-switch svg { width: 16px; height: 16px; }
  @media screen and (max-width: 820px) { .mfc-switch { min-height: 44px; } }
  .mfc-table { overflow-x: auto; }
  .mfc-table td.num, .mfc-table th.num { text-align: right; white-space: nowrap; }
  .mfc-table .mfc-part { color: var(--muted); font-weight: 400; }
  .skel.mfc-skel { height: calc(var(--mfc-h) + 30px); border-radius: 12px; }
  /* Horizontal bars */
  .mfc-rows { display: flex; flex-direction: column; gap: 6px; margin: 0; padding: 0; list-style: none; }
  .mfc-row { display: grid; grid-template-columns: minmax(0, min(var(--mfc-lw, 160px), 40%)) minmax(0, 1fr); align-items: center;
    gap: 2px 14px; padding: 5px 6px; margin: 0 -6px; border-radius: 8px; }
  .mfc-row:hover { background: color-mix(in srgb, var(--brand) 5%, transparent); }
  .mfc-rl { min-width: 0; font-size: 14.5px; font-weight: 600; line-height: 1.3; color: var(--ink); overflow-wrap: anywhere; }
  .mfc.is-measuring .mfc-rl { white-space: nowrap; }   /* MF.chart reads each label's one-line width, then wraps again */
  .mfc-rt { position: relative; height: 22px; margin: 0 var(--mfc-vr, 88px) 0 var(--mfc-vl, 0px); }
  .mfc-row .mfc-bar { top: 50%; bottom: auto; left: calc(var(--lo) * 100%); width: calc((var(--hi) - var(--lo)) * 100%); min-width: 2px;
    height: 14px; min-height: 0; transform: translateY(-50%); transform-origin: 0 50%; border-radius: 0 4px 4px 0; }
  .mfc-row.neg .mfc-bar { top: 50%; border-radius: 4px 0 0 4px; background: var(--chart-neg); transform-origin: 100% 50%; }
  .mfc-row.zero .mfc-bar { display: none; }
  .mfc-row:hover .mfc-bar { background: var(--chart-bar-hover); }
  .mfc-row.neg:hover .mfc-bar { background: var(--chart-neg-hover); }
  .mfc-hbar.is-new .mfc-bar { animation-name: mfc-grow-x; }
  @keyframes mfc-grow-x { from { scale: 0 1; } }
  .mfc-rt .mfc-val { top: 50%; bottom: auto; left: calc(var(--hi) * 100% + 8px); transform: translateY(-50%); visibility: visible;
    font: 400 14px/1.2 var(--font-body); color: var(--muted); }
  .mfc-rt .mfc-val b { font-weight: 700; color: var(--ink); }
  .mfc-row.neg .mfc-val { left: auto; right: calc((1 - var(--lo)) * 100% + 8px); }
  .mfc-rt.has-zero::before { content: ""; position: absolute; top: -7px; bottom: -7px; left: calc(var(--z) * 100%); width: 1px;
    background: var(--chart-zero); }
  .mfc-row[data-tone] .mfc-bar { background: var(--mfc-tone); }
  .mfc-row[data-tone]:hover .mfc-bar { background: var(--mfc-tone); filter: brightness(.92); }
  [data-tone="ok"] { --mfc-tone: var(--ok); } [data-tone="info"] { --mfc-tone: var(--info-fg); }
  [data-tone="warn"] { --mfc-tone: var(--warn-fg); } [data-tone="danger"] { --mfc-tone: var(--danger); }
  [data-tone="neutral"] { --mfc-tone: var(--dot-neutral); } [data-tone="gold"] { --mfc-tone: var(--chart-bar); }
  [data-tone="brand"] { --mfc-tone: var(--brand); }
  @container (max-width: 420px) {                     /* narrow card: the label on its own line, the bar the full width */
    .mfc-row { grid-template-columns: minmax(0, 1fr); }
  }
  /* Inline meter in a table cell (static markup, no JS): <span class="mfc-meter" style="--v:.62" aria-hidden="true"></span>
     beside the number it shows. data-tone as above. */
  .mfc-meter { position: relative; display: inline-block; width: 100%; max-width: 160px; height: 8px; overflow: hidden;
    border-radius: 999px; background: var(--chip); vertical-align: middle; }
  .mfc-meter::after { content: ""; position: absolute; inset: 0 auto 0 0; width: calc(var(--v, 0) * 100%); border-radius: inherit;
    background: var(--mfc-tone, var(--chart-bar)); }

  /* Printable document (.print-doc): a sheet on screen, the page itself on paper. A contract, a timesheet, an
     invoice summary, a deviation or audit report. Header: the wordmark (MF.logo), a kicker + title, and the facts
     that identify the document; body: the page's own content; a signature block; a footer line. Page numbers come
     from @page in the print layer (Chrome/Edge 131+), so the footer does not repeat them.
       <article class="print-doc">
         <header class="pd-head"><div class="pd-brand">MF.logo({size: 28})</div>
           <div class="pd-title"><span class="kicker muted">Timeliste</span><h1>Kari Nordmann</h1><p>september 2026</p></div>
           <dl class="pd-meta"><dt>Kunde</dt><dd>Bergen kommune</dd> … <dt>Utskrevet</dt><dd>25. sep. 2026</dd></dl></header>
         <div class="pd-body"> … tables, dl.facts … </div>
         <div class="sig-block"><div class="sig"><span class="sig-line"></span><span class="sig-name">Kari Nordmann</span>
           <span class="sig-role">Fagperson · dato</span></div> … </div>
         <footer class="pd-foot">Mediflora AS · Helse og omsorg når du trenger det</footer></article> */
  .print-doc { max-width: 820px; margin: 0 auto; padding: 40px 44px 32px; background: var(--surface); color: var(--ink);
    border: 1px solid var(--line); border-radius: 12px; box-shadow: var(--sheet-shadow); }
  .pd-head { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 18px 28px; align-items: start; padding-bottom: 20px;
    margin-bottom: 22px; border-bottom: 2px solid var(--ink); }
  .pd-brand { grid-column: 1 / -1; }
  .pd-title h1 { margin: 4px 0 0; font: 700 24px/1.2 var(--font-head); letter-spacing: -.3px; }
  .pd-title p { margin: 4px 0 0; font-size: var(--fs-md); color: var(--muted); }
  dl.pd-meta { display: grid; grid-template-columns: auto auto; gap: 3px 14px; margin: 4px 0 0; font-size: var(--fs-sm); }
  dl.pd-meta dt { color: var(--muted); }
  dl.pd-meta dd { margin: 0; font-weight: 600; text-align: right; font-variant-numeric: tabular-nums; }
  .pd-body h2 { margin: 26px 0 10px; font: 700 16px/1.3 var(--font-head); }
  .pd-body > :first-child { margin-top: 0; }
  .pd-foot { margin-top: 28px; padding-top: 12px; border-top: 1px solid var(--line); font-size: var(--fs-xs); color: var(--muted); }
  /* Signature block: two or three lines side by side (one per party), each a ruled line with the name and role
     under it. Stays together on one page. */
  .sig-block { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 28px 36px; margin-top: 36px; break-inside: avoid; }
  .sig { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
  .sig-line { display: block; height: 48px; border-bottom: 1px solid var(--ink); }
  .sig-name { margin-top: 6px; font-weight: 600; overflow-wrap: anywhere; }
  .sig-role { font-size: var(--fs-xs); color: var(--muted); }
  @media screen and (max-width: 560px) {
    .print-doc { padding: 22px 18px; }
    .pd-head { grid-template-columns: minmax(0, 1fr); }
    dl.pd-meta dd { text-align: left; }
  }

  /* ══ v3 additions ══════════════════════════════════════════════════════════════════════════════════
     All opt-in: new class names, or a name a portal already uses for the SAME thing (its inline copy keeps
     winning until the page deletes it). Collisions checked against all three portals (2026-09-24):
       · admin ul.inbox (list-page inbox rows) is not the two-pane card: the card rule skips ul/ol.
       · admin .panel.riskmx only wraps its own matrix: the shared matrix is table.riskmx, nothing else.
       · admin .seg / .chat / .typing-ind / .replybar and Min side .inbox* / .chat set every property the
         shared rule sets, so they look exactly as before. Customer .skel picks up the pulse (it IS a
         loading placeholder) and nothing else.
     Row and bubble parts get NEW names (.inbox-row, .bubble): aliasing the old .msgrow / .bub would leak
     Min side's gaps into admin's differently built rows. The mapping is in the shared-additions notes. */

  /* Loading placeholders. Flat --chip-hover shapes with a calm opacity pulse (no gradient shimmer), and no
     motion under prefers-reduced-motion. The shapes are decoration: wrap them in aria-hidden and give screen
     readers ONE status text beside them:
       <div class="skel-wrap"><span class="sr-only" role="status">Laster…</span>
         <div class="skel-rows" aria-hidden="true">…</div></div>
     MF.skel('rows' | 'table' | 'cards' | 'lines', n) returns exactly that markup.
     Pieces: .skel (a block: 100% × 16px unless you size it), .skel-line (a 12px text line; .lg 18px = a heading;
     .inline = a value inside a sentence or a dd, as the customer portal's SKEL), .skel-circle (an avatar: 40px,
     .sm 32, .lg 64). Line width: style="--w:60%" (default 100%; .inline 160px).
     Ready-made patterns (widths vary by row, so they read as content, not stripes):
       .skel-rows  > .skel-row  (avatar + two lines + a trailing pill: lists, inboxes, queues)
       .skel-table > .skel-tr   (header row + rows; one .skel-line per column, any number of columns)
       .skel-cards > .skel-card (tile grids)  ·  .skel-lines (a paragraph) */
  @keyframes mf-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }
  .skel, .skel-line, .skel-circle { display: block; background: var(--skel); border-radius: 6px;
    outline: 1px solid transparent; outline-offset: -1px;   /* forced colours drop the fill; the outline keeps the shape */
    animation: mf-pulse 1.8s ease-in-out infinite; }
  .skel { width: var(--w, 100%); height: var(--h, 16px); border-radius: var(--radius-sm); }
  .skel-line { width: var(--w, 100%); max-width: 100%; height: 12px; }
  .skel-line.lg { height: 18px; border-radius: 8px; }
  .skel-line.inline { display: inline-block; width: var(--w, min(160px, 70%)); vertical-align: middle; }
  .skel-line + .skel-line { margin-top: 9px; }
  .skel-circle { flex-shrink: 0; width: 40px; height: 40px; border-radius: 50%; }
  .skel-circle.sm { width: 32px; height: 32px; }
  .skel-circle.lg { width: 64px; height: 64px; }
  .skel-wrap { position: relative; }   /* keeps the sr-only status inside a scrolling panel */
  .skel-stack { flex: 1; min-width: 0; }
  .skel-rows { display: flex; flex-direction: column; }
  .skel-row { display: flex; align-items: center; gap: 12px; padding: 14px 18px; border-bottom: 1px solid var(--line-soft); }
  .skel-row:last-child { border-bottom: 0; }
  .skel-row > .skel-line { flex: 0 0 64px; height: 22px; border-radius: 999px; }   /* trailing badge */
  .skel-stack > .skel-line:first-child { width: 38%; }
  .skel-stack > .skel-line:nth-child(2) { width: 72%; }
  .skel-row:nth-child(3n+2) .skel-stack > .skel-line:first-child { width: 52%; }
  .skel-row:nth-child(3n+2) .skel-stack > .skel-line:nth-child(2) { width: 58%; }
  .skel-row:nth-child(3n) .skel-stack > .skel-line:first-child { width: 30%; }
  .skel-row:nth-child(3n) .skel-stack > .skel-line:nth-child(2) { width: 80%; }
  .skel-table { display: flex; flex-direction: column; }
  .skel-tr { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); align-items: center; gap: 16px;
    padding: 15px 12px; border-bottom: 1px solid var(--line-soft); }
  .skel-tr:first-child { padding-block: 10px 11px; border-bottom-color: var(--line); }
  .skel-tr:last-child { border-bottom: 0; }
  .skel-tr > .skel-line { margin: 0; width: 64%; }
  .skel-tr > .skel-line:first-child { width: 82%; }
  .skel-tr > .skel-line:nth-child(3n) { width: 46%; }
  .skel-tr:nth-child(odd) > .skel-line:first-child { width: 66%; }
  .skel-tr:nth-child(3n) > .skel-line:nth-child(2) { width: 50%; }
  .skel-tr:nth-child(even) > .skel-line:nth-child(2) { width: 80%; }
  .skel-tr:nth-child(3n+1) > .skel-line:last-child { width: 34%; }
  .skel-tr:nth-child(4n+2) > .skel-line:nth-child(3) { width: 72%; }
  .skel-tr:first-child > .skel-line:nth-child(n) { width: 44%; height: 9px; }   /* column headers (:nth-child(n) outranks the row widths above) */
  .skel-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 14px; }
  .skel-card { display: flex; flex-direction: column; gap: 10px; padding: 18px; background: var(--surface);
    border: 1px solid var(--line); border-radius: var(--radius); }
  .skel-card > .skel-line { margin: 0; }
  .skel-card > .skel-line:last-child { width: 55%; }
  .skel-head { display: flex; align-items: center; gap: 12px; margin-bottom: 4px; }
  .skel-head .skel-line:first-child { width: 70%; }
  .skel-head .skel-line:nth-child(2) { width: 45%; }
  .skel-lines > .skel-line:nth-child(3n+2) { width: 92%; }
  .skel-lines > .skel-line:last-child:not(:first-child) { width: 56%; }
  @media (prefers-reduced-motion: reduce) { .skel, .skel-line, .skel-circle { animation: none; } }

  /* Phone tables: table.mf-stack turns every row into a card at ≤820px (the portals' phone breakpoint) and is an
     ordinary table above it. Markup: each <td> after the first carries data-label="<its column name>" (the
     <th> text); the FIRST cell is the card title; a last td.actions holds the row's buttons (full width, 44px);
     td.full spans the card; an empty td or td.nil ("—") is hidden. Numbers go left under their label.
     Inside a .panel the cards are hairline-separated blocks; .cards makes each row its own bordered card (a table
     that is not already in a card). Screen readers hear "label value" from the ::before text; the thead is hidden.
     .facts: one "label … value" line per cell instead of the two-column grid (Min side's phone tables). */
  table.mf-stack td.actions { white-space: nowrap; }
  table.mf-stack td.actions .btn { vertical-align: middle; }   /* an icon-only button has no text baseline */
  @media screen and (max-width: 820px) {
    table.mf-stack, table.mf-stack > tbody { display: block; width: 100%; }
    table.mf-stack > thead { display: none; }
    table.mf-stack > tbody > tr { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px 16px;
      padding: 14px 2px; border-bottom: 1px solid var(--line); }
    table.mf-stack > tbody > tr:last-child { border-bottom: 0; }
    table.mf-stack > tbody > tr > td { display: block; min-width: 0; padding: 0; border: 0; text-align: start !important;
      white-space: normal; overflow-wrap: anywhere; }
    table.mf-stack > tbody > tr > td:first-child { grid-column: 1 / -1; font-size: var(--fs-md); font-weight: 600; }
    table.mf-stack > tbody > tr > :is(td.full, td.actions, td:not([data-label])) { grid-column: 1 / -1; }
    table.mf-stack > tbody > tr > td[data-label]:not(:first-child, .actions)::before { content: attr(data-label); display: block;
      margin-bottom: 2px; font-size: var(--fs-xs); font-weight: 600; line-height: 1.35; color: var(--muted); }
    table.mf-stack > tbody > tr > td.actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding-top: 10px;
      border-top: 1px solid var(--line-soft); }
    table.mf-stack > tbody > tr > td.actions :is(.btn, button) { min-height: 44px; }
    table.mf-stack > tbody > tr > td.actions .btn.icon-only { width: 44px; }
    table.mf-stack > tbody > tr > td:is(:empty, .nil) { display: none; }
    table.mf-stack.cards > tbody { display: flex; flex-direction: column; gap: 10px; }
    table.mf-stack.cards > tbody > tr { padding: 14px 16px; border: 1px solid var(--line); border-radius: var(--radius);
      background: var(--surface); box-shadow: var(--shadow); }
    table.mf-stack.cards > tbody > tr:last-child { border-bottom: 1px solid var(--line); }
    /* .facts: one "label ... value" line per cell, like dl.facts (Min side's phone tables): for 3–5 short columns. */
    table.mf-stack.facts > tbody > tr { display: block; padding: 12px 0; border-bottom-color: var(--line-soft); }
    table.mf-stack.facts > tbody > tr:last-child { border-bottom: 0; }
    table.mf-stack.facts > tbody > tr > td { display: flex; align-items: center; justify-content: space-between; gap: 12px;
      padding: 3px 0; text-align: end !important; }
    table.mf-stack.facts > tbody > tr > td[data-label]:not(:first-child, .actions)::before { flex-shrink: 0; margin: 0;
      font-size: var(--fs-sm); font-weight: 400; text-align: start; }
    table.mf-stack.facts > tbody > tr > td:first-child { display: block; padding-bottom: 6px; text-align: start !important; }
    table.mf-stack.facts > tbody > tr > td.actions { justify-content: flex-start; margin-top: 6px; padding-top: 10px; }
  }

  /* Segmented control: 2–5 mutually exclusive options in one bordered pill. The chosen one is filled --brand-dark,
     the same "on" as a pressed chip. Two markups:
       a VALUE (a form field, a permission level): native radios, which bring Tab + arrow keys for free
         <div class="seg sm" role="radiogroup" aria-label="Rekrutterer: Oppdrag">
           <label><input type="radio" name="lvl-rec-oppdrag" value="none" checked>Ingen</label> … </div>
       a VIEW switch: buttons in role="group" with aria-pressed (+ .on), as admin's toggles do today.
     (button role="radio" + aria-checked also styles, but then the page owes roving tabindex and arrow keys.)
     States: checked · :focus-visible (ring inside the pill; white on the fill) · disabled (an option, or
     aria-disabled on the group) · .changed = edited, not yet saved (gold ring + gold-soft options; also add an
     sr-only "(endret)"). Sizes: default 36px, .sm 28px for dense grids; 44px on phones. .block = full width. */
  .seg { display: inline-flex; border: 1px solid var(--line-strong); border-radius: var(--radius-sm); overflow: hidden; }
  .seg > :is(button, label, a) { display: inline-flex; align-items: center; gap: 6px; margin: 0;
    padding: 8px 12px; border: 0; background: var(--surface); font: inherit; font-size: 14px; font-weight: 600;
    line-height: 20px; color: var(--muted); text-decoration: none; cursor: pointer; -webkit-tap-highlight-color: transparent;
    transition: background-color .12s, color .12s; }
  .seg > * > svg { width: 16px; height: 16px; flex-shrink: 0; }
  .seg > :is(button, a):not(:disabled, [aria-disabled=true], .on, [aria-pressed=true], [aria-checked=true]):hover,
  .seg > label:not(:has(> input:checked, > input:disabled)):hover { background: var(--chip); color: var(--ink); }
  .seg > :is(.on, [aria-pressed=true], [aria-checked=true]),
  .seg > label:has(> input:checked) { background: var(--brand-dark); color: var(--on-brand); }
  /* The radio stays in the page (focusable, announced) but invisible over its label, so a click hits it directly. */
  .seg > label { position: relative; }
  .seg > label > input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: inherit; }
  /* The pill clips its overflow, so the ring is drawn inside the option; on the fill it turns white. */
  .seg > :is(button, a):focus-visible { outline-offset: -3px; }
  .seg > label:has(> input:focus-visible) { outline: 3px solid var(--focus); outline-offset: -3px; }
  .seg > :is(.on, [aria-pressed=true], [aria-checked=true]):focus-visible,
  .seg > label:has(> input:checked:focus-visible) { outline: 2px solid var(--on-brand); outline-offset: -5px; }
  .seg > :is(:disabled, [aria-disabled=true]), .seg > label:has(> input:disabled) { opacity: .5; cursor: not-allowed; }
  .seg[aria-disabled=true] { opacity: .6; }
  .seg[aria-disabled=true] > * { pointer-events: none; }
  .seg.changed { border-color: var(--gold-dark); box-shadow: 0 0 0 1px var(--gold-dark); }
  .seg.changed > :not(.on, [aria-pressed=true], [aria-checked=true]):not(:has(> input:checked)) { background: var(--gold-soft); color: var(--gold-ink); }
  .seg.sm > :is(button, label, a) { padding: 4px 10px; font-size: 13px; line-height: 18px; }
  .seg.block { display: flex; width: 100%; }
  .seg.block > * { flex: 1 1 0; min-width: 0; justify-content: center; }
  @media screen and (max-width: 820px) { .seg > :is(button, label, a) { min-height: 44px; min-width: 44px; } }

  /* Inbox + chat: the Min side two-pane look, shared. List on the left, the open conversation on the right from
     1100px; below that ONE pane: the list, or (with .thread) the conversation with a back button.
       <div class="inbox [thread]">
         <nav class="inbox-list" aria-label="Samtaler">  button.inbox-row × n  </nav>
         <section class="inbox-pane" aria-labelledby="…">
           .thread-head (button.thread-back + h2 + .inbox-with) · .chat (bubble rows) · .typing-ind · .replybar
         </section></div>
     Row: button.inbox-row[.unread][aria-current=true] > .avatar.sm.soft + .inbox-main > .inbox-top (.inbox-subj +
     time.inbox-time with a leading .inbox-dot when unread) + .inbox-with + .inbox-snip; plus sr-only "(ulest)".
     .inbox-list also works alone (in a .panel) for an inbox-style list without a reading pane.
     Bubble: .bubble-row.mine|.theirs|.sys > [.avatar.sm] + .bubble.mine|.theirs|.sys > .bubble-meta + .bubble-text
     (a .bubble straight inside .chat aligns itself). Mine = gold fill (dark text), theirs = white with a hairline,
     sys = a quiet centred note. Heights: --inbox-h (two panes) and --thread-h (one-pane thread) default to Min
     side's offsets; set them on the .inbox for another page shell. */
  .inbox:not(ul, ol) { display: grid; grid-template-columns: minmax(0, 1fr); background: var(--surface);
    border: 1px solid var(--line); border-radius: var(--radius-lg); box-shadow: var(--shadow); overflow: hidden; }
  .inbox-list { min-width: 0; overflow: auto; }
  :is(ul, ol).inbox-list { margin: 0; padding: 0; list-style: none; }
  .inbox-pane { min-width: 0; min-height: 0; display: none; flex-direction: column; }
  .inbox.thread .inbox-list { display: none; }
  .inbox.thread .inbox-pane { display: flex; }
  .inbox.thread { height: var(--thread-h, calc(100dvh - 100px)); min-height: 360px; grid-template-rows: minmax(0, 1fr); }
  @media (min-width: 1100px) {
    .inbox:not(ul, ol), .inbox.thread { grid-template-columns: minmax(260px, 340px) minmax(0, 1fr); grid-template-rows: minmax(0, 1fr);
      height: var(--inbox-h, calc(100dvh - 184px)); min-height: 460px; }
    .inbox .inbox-list, .inbox.thread .inbox-list { display: block; border-right: 1px solid var(--line); }
    .inbox .inbox-pane { display: flex; }
    .inbox .thread-back { display: none; }
  }
  .inbox-empty { display: grid; place-items: center; flex: 1; min-height: 380px; }
  .inbox-row { display: flex; align-items: flex-start; gap: 12px; width: 100%; margin: 0; padding: 14px 18px; border: 0;
    border-bottom: 1px solid var(--line-soft); background: none; font: inherit; color: inherit; text-align: left; cursor: pointer; }
  .inbox-row:last-child, .inbox-list > li:last-child > .inbox-row { border-bottom: 0; }
  .inbox-row:hover { background: var(--hover-soft); }
  .inbox-row:is([aria-current=true], [aria-current=page]) { background: var(--brand-soft); }
  .inbox-row:is([aria-current=true], [aria-current=page]) .avatar.soft { background: var(--surface); }
  .inbox-row:focus-visible { outline-offset: -3px; }
  .inbox-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
  .inbox-top { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
  .inbox-subj { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }
  .inbox-row.unread .inbox-subj { font-weight: 800; }
  .inbox-time { display: inline-flex; align-items: center; gap: 6px; flex-shrink: 0; font-size: var(--fs-xs); color: var(--muted); white-space: nowrap; }
  .inbox-row.unread .inbox-time { color: var(--accent); font-weight: 700; }
  .inbox-dot { flex-shrink: 0; width: 8px; height: 8px; border-radius: 50%; background: var(--accent); }
  .inbox-with { font-size: 13px; color: var(--muted); }
  .inbox-snip { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--fs-sm); color: var(--muted); }
  .inbox-row.unread .inbox-snip { color: var(--ink); }
  .thread-head { display: flex; align-items: center; gap: 12px; min-height: 68px; padding: 14px 20px; border-bottom: 1px solid var(--line); }
  .thread-head > div { min-width: 0; }
  .thread-head h2 { margin: 0; font-size: 19px; font-weight: 600; line-height: 1.3; overflow-wrap: anywhere; }
  .thread-back { flex-shrink: 0; }   /* a long subject must not squeeze the back button */
  .chat { display: flex; flex-direction: column; gap: 12px; padding: 20px; overflow: auto; background: var(--bg); }
  .inbox-pane > .chat { flex: 1 1 auto; min-height: 0; }
  .bubble-row { display: flex; align-items: flex-end; gap: 8px; }
  .bubble-row.mine { justify-content: flex-end; }
  .bubble-row.theirs { justify-content: flex-start; }
  .bubble-row.sys { justify-content: center; }
  .bubble-row .avatar.soft { background: var(--surface); box-shadow: inset 0 0 0 1px var(--line); }   /* like the white bubble beside it */
  .bubble { max-width: 74%; padding: 9px 13px; border-radius: 16px; }
  .chat > .bubble.mine { align-self: flex-end; }
  .chat > .bubble.theirs { align-self: flex-start; }
  .chat > .bubble.sys { align-self: center; }
  .bubble.theirs { background: var(--surface); border: 1px solid var(--line); border-bottom-left-radius: 4px; }
  .bubble.mine { background: var(--gold); color: var(--on-gold); border-bottom-right-radius: 4px; }
  .bubble.sys { max-width: 86%; padding: 6px 12px; border-radius: 12px; background: var(--chip); color: var(--muted); text-align: center; }
  .bubble-meta { margin-bottom: 3px; font-size: 12px; opacity: .78; }
  .bubble.sys .bubble-meta { opacity: 1; }   /* muted on chip is already the floor for contrast */
  .bubble-text { font-size: 14.5px; line-height: 1.45; white-space: pre-wrap; overflow-wrap: break-word; }
  .bubble.sys .bubble-text { font-size: 13px; }
  @keyframes mf-typing { 0%, 60%, 100% { opacity: .3; } 30% { opacity: 1; } }
  .typing-ind { display: flex; align-items: center; gap: 4px; padding: 4px 18px 10px; color: var(--muted); font-size: 13px; font-style: italic; }
  .typing-ind i { display: inline-block; width: 5px; height: 5px; border-radius: 50%; background: var(--muted); animation: mf-typing 1.2s infinite; }
  .typing-ind i:nth-child(3) { animation-delay: .2s; }
  .typing-ind i:nth-child(4) { animation-delay: .4s; }
  .replybar { display: flex; align-items: flex-end; gap: 10px; padding: 12px 14px; border-top: 1px solid var(--line); background: var(--surface); }
  .replybar textarea { flex: 1; min-height: 44px; }
  @media screen and (max-width: 820px) { .replybar .btn, .thread-back { min-height: 44px; } .thread-back.icon-only { width: 44px; } }

  /* Preview frame: "this is how it will look" around an e-mail, a news post or a job card, before it goes out.
       <figure class="preview-frame w-mail">
         <div class="pv-bar"><div class="pv-label"><span class="kicker muted">Forhåndsvisning</span><b>Velkommen</b></div>
           <div class="pv-tools">.seg.sm (Desktop | Mobil, or Kort | Artikkel) and/or a .btn.ghost.sm</div></div>
         <div class="pv-stage"><div class="pv-canvas"> dl.pv-meta (Fra / Til / Emne) + the rendered content,
           or an <iframe sandbox srcdoc> for server-rendered e-mail HTML </div></div>
         <figcaption class="pv-foot">Eksempelverdier …</figcaption></figure>
     Canvas widths: .w-mail 600px · .w-card 380px · .w-article 760px · .w-phone 390px (on the figure or the canvas);
     swap the class to switch view. .pv-canvas.bare drops the white sheet for content that is its own card.
     Merge fields: .merge-chips > button.merge-chip (label + code "{{FirstName}}") inserts a field at the caret;
     a span.merge-chip marks a field inside text. */
  .preview-frame { display: flex; flex-direction: column; min-width: 0; margin: 0; background: var(--surface);
    border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow); overflow: hidden; }
  .pv-bar { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 12px;
    padding: 10px 12px 10px 16px; border-bottom: 1px solid var(--line); background: var(--surface); }
  .pv-label { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
  .pv-label b { font: 600 15px/1.3 var(--font-head); color: var(--ink); overflow-wrap: anywhere; }
  .pv-tools { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
  .pv-stage { flex: 1; min-width: 0; padding: 24px; background: var(--bg); overflow: auto; }
  .pv-canvas { max-width: var(--pv-w, 100%); margin: 0 auto; background: var(--surface); border-radius: 12px;
    box-shadow: var(--sheet-shadow); overflow: hidden; }
  .pv-canvas.bare { background: none; border-radius: 0; box-shadow: none; overflow: visible; }
  .pv-canvas > iframe { display: block; width: 100%; min-height: 480px; border: 0; background: var(--surface); }
  :is(.preview-frame, .pv-canvas).w-mail { --pv-w: 600px; }
  :is(.preview-frame, .pv-canvas).w-card { --pv-w: 380px; }
  :is(.preview-frame, .pv-canvas).w-article { --pv-w: 760px; }
  :is(.preview-frame, .pv-canvas).w-phone { --pv-w: 390px; }
  dl.pv-meta { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 4px 12px; margin: 0; padding: 14px 18px;
    border-bottom: 1px solid var(--line); background: var(--surface); font-size: var(--fs-sm); }
  dl.pv-meta > dt { margin: 0; color: var(--muted); }
  dl.pv-meta > dd { margin: 0; min-width: 0; color: var(--ink); overflow-wrap: anywhere; }
  .pv-foot { margin: 0; padding: 10px 16px; border-top: 1px solid var(--line); font-size: 13px; line-height: 1.45; color: var(--muted); }
  @media screen and (max-width: 560px) { .pv-stage { padding: 12px; } }
  .merge-chips { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
  .merge-chip { display: inline-flex; align-items: center; gap: 6px; padding: 1px 7px; border: 1px solid var(--merge-line);
    border-radius: 7px; background: var(--brand-soft); color: var(--brand-dark); font: inherit; font-size: 13px;
    font-weight: 600; line-height: 1.45; white-space: nowrap; vertical-align: baseline; }
  .merge-chip code { font: 500 11.5px/1.3 ui-monospace, 'Cascadia Mono', Consolas, monospace; color: var(--brand); }
  .merge-chip svg { width: 14px; height: 14px; flex-shrink: 0; }
  button.merge-chip { min-height: 32px; padding: 4px 10px; cursor: pointer; transition: background-color .12s, border-color .12s; }
  button.merge-chip:hover { background: var(--merge-hover); border-color: var(--merge-hover-line); }
  button.merge-chip:focus-visible { outline-offset: 1px; }
  @media screen and (max-width: 820px) { button.merge-chip { min-height: 44px; } }

  /* Calendar bits. An event is a flat .cal-chip with a status DOT (never a left border): the dot takes a tone
     class (.tone-info planned · .tone-ok sent/confirmed · .tone-warn needs a reply · .tone-danger cancelled or
     clashing · .tone-gold waiting on you · .tone-neutral done); put the status in text too (sr-only or title).
       <button class="cal-chip"><span class="cal-dot tone-ok"></span><span class="cal-t">09:00</span>
         <span class="cal-title">Oppfølging Bergen</span><span class="cal-sub">Bergen kommune</span></button>
     .wrap lets the title take two lines (week columns); by default it is one line with an ellipsis (month cells).
     Day numbers: .cal-num (26px, quiet) and .cal-today (gold-filled circle, dark number; add aria-current="date").
     .cal-num.lg (34px) for a week-view header. The grid itself stays in the page. */
  .cal-chip { display: flex; flex-wrap: wrap; align-items: center; column-gap: 6px; width: 100%; min-width: 0; margin: 0;
    padding: 4px 8px; border: 0; border-radius: 8px; background: var(--chip); color: var(--ink); font: inherit;
    font-size: var(--fs-xs); line-height: 1.35; text-align: left; text-decoration: none; }
  :is(button, a).cal-chip { cursor: pointer; transition: background-color .12s; }
  :is(button, a).cal-chip:hover { background: var(--chip-hover); color: var(--ink); }
  .cal-dot { flex-shrink: 0; width: 8px; height: 8px; border-radius: 50%; background: var(--neutral-fg); }
  .cal-dot.tone-ok { background: var(--ok); }
  .cal-dot.tone-info { background: var(--info-fg); }
  .cal-dot.tone-warn { background: var(--warn-fg); }
  .cal-dot.tone-danger { background: var(--danger); }
  .cal-dot.tone-gold { background: var(--gold-dark); box-shadow: inset 0 0 0 1px rgba(122, 91, 12, .35); }
  .cal-dot.tone-neutral { background: var(--dot-neutral); }
  .cal-t { flex-shrink: 0; color: var(--muted); font-variant-numeric: tabular-nums; }
  .cal-title { flex: 1 1 7em; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }   /* drops under the time when the chip is narrow */
  .cal-chip.wrap .cal-title { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; white-space: normal; overflow-wrap: anywhere; }   /* week view: two lines */
  .cal-sub { flex-basis: 100%; min-width: 0; padding-left: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--muted); }
  .cal-num, .cal-today { display: inline-grid; place-items: center; min-width: 26px; height: 26px; padding: 0 5px; border-radius: 999px;
    font: 600 13px/1 var(--font-head); font-variant-numeric: tabular-nums; color: var(--muted); }
  .cal-num.lg { min-width: 34px; height: 34px; font-size: 17px; color: var(--ink); }
  .cal-today, .cal-num.cal-today { background: var(--gold); color: var(--on-gold); font-weight: 700; }
  @media screen and (max-width: 820px) { :is(button, a).cal-chip { min-height: 44px; } }

  /* Risk matrix (likelihood × consequence): cells tinted by band with the tone pairs, the score in ink, and each
     risk as a white ID chip. low = ok · medium = warn · high = danger · critical = a deeper danger tint. No heat-map
     rainbow, no solid fills. A real table, so screen readers get row and column headers:
       <div class="riskmx-wrap"><span class="rm-axis y" aria-hidden="true">Konsekvens</span>
         <table class="riskmx"><caption class="sr-only">…</caption>
           <thead><tr><td></td><th scope="col">1</th>…<th scope="col">5</th></tr></thead>
           <tbody><tr><th scope="row">5</th><td class="rm-med"><span class="rm-n">5</span></td> …
             <td class="rm-crit"><span class="rm-n">25</span><span class="rm-ids"><button class="rm-id">R-12</button></span></td>
         </tbody></table>
         <span class="rm-axis x" aria-hidden="true">Sannsynlighet</span></div>
       <ul class="rm-legend"><li><span class="rm-key rm-low"></span>Lav</li> …</ul>
     Band thresholds come from the data (RiskService: high ≥ 15, medium ≥ 8); critical is optional. */
  .riskmx-wrap { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: center; gap: 6px 8px; min-width: 0; }
  .rm-axis { font-size: var(--fs-xs); font-weight: 700; letter-spacing: .3px; color: var(--muted); }
  .rm-axis.y { writing-mode: vertical-rl; transform: rotate(180deg); justify-self: center; }
  .rm-axis.x { grid-column: 2; justify-self: center; }
  table.riskmx { width: 100%; border-collapse: separate; border-spacing: 4px; table-layout: fixed; font-size: var(--fs-sm); }
  table.riskmx :is(th, td) { border: 0; text-align: center; vertical-align: middle; }
  table.riskmx th { padding: 2px; background: none; font: 600 12.5px/1 var(--font-head); color: var(--muted); }
  table.riskmx :is(thead td:first-child, th[scope=row]) { width: 26px; padding: 0; }
  table.riskmx thead td { height: auto; background: none; box-shadow: none; }
  table.riskmx td { height: 58px; padding: 6px 4px; border-radius: 10px; background: var(--neutral-bg); color: var(--ink); }
  table.riskmx td.rm-low { background: var(--ok-bg); box-shadow: inset 0 0 0 1px rgba(6, 118, 71, .14); }
  table.riskmx td.rm-med { background: var(--warn-bg); box-shadow: inset 0 0 0 1px rgba(168, 67, 10, .16); }
  table.riskmx td.rm-high { background: var(--danger-bg); box-shadow: inset 0 0 0 1px rgba(180, 35, 24, .18); }
  table.riskmx td.rm-crit { background: var(--crit-bg); box-shadow: inset 0 0 0 1px rgba(180, 35, 24, .32); }
  .rm-n { display: block; font: 600 14px/1.1 var(--font-head); font-variant-numeric: tabular-nums; color: var(--ink); }
  .rm-ids { display: flex; flex-wrap: wrap; justify-content: center; gap: 4px; margin-top: 5px; }
  .rm-id { display: inline-flex; align-items: center; min-height: 22px; padding: 1px 7px; border: 1px solid var(--rm-id-line);
    border-radius: 999px; background: var(--surface); color: var(--ink); font: 700 11.5px/1.3 var(--font-body); white-space: nowrap; }
  button.rm-id { cursor: pointer; }
  button.rm-id:hover { border-color: rgba(15, 34, 51, .4); }
  .rm-legend { display: flex; flex-wrap: wrap; gap: 6px 18px; margin: 12px 0 0; padding: 0; list-style: none; font-size: var(--fs-xs); color: var(--muted); }
  .rm-legend li { display: inline-flex; align-items: center; gap: 7px; }
  .rm-key { width: 14px; height: 14px; border-radius: 4px; background: var(--neutral-bg); }
  .rm-key.rm-low { background: var(--ok-bg); box-shadow: inset 0 0 0 1px rgba(6, 118, 71, .3); }
  .rm-key.rm-med { background: var(--warn-bg); box-shadow: inset 0 0 0 1px rgba(168, 67, 10, .3); }
  .rm-key.rm-high { background: var(--danger-bg); box-shadow: inset 0 0 0 1px rgba(180, 35, 24, .3); }
  .rm-key.rm-crit { background: var(--crit-bg); box-shadow: inset 0 0 0 1px rgba(180, 35, 24, .45); }
  @media screen and (max-width: 820px) { button.rm-id { min-width: 44px; min-height: 44px; justify-content: center; } }   /* phones: a whole 44px target */
  @media screen and (max-width: 560px) { table.riskmx { border-spacing: 3px; } table.riskmx td { height: 52px; padding: 4px 2px; } }

  /* Tones: status badges (b-*), tone modifiers (.tone-*) and category badges. Kept after .chip / .ic-tile /
     .avatar on purpose: a .tone-* class on any of them wins over its neutral background. */
  .tone-ok, .b-ok,
  .b-active, .b-approved, .b-verified, .b-qualified, .b-accepted, .b-paid, .b-won, .b-signed, .b-filled,
  .b-published, .b-invited, .b-hired, .b-handled { background: var(--ok-bg); color: var(--ok-fg); }
  .tone-info, .b-info,
  .b-pending, .b-submitted, .b-under_review, .b-sent, .b-new, .b-confirmed, .b-bidding, .b-proposal,
  .b-negotiation, .b-prospect, .b-profile_review, .b-screening_call, .b-sourced, .b-contacted, .b-candidate,
  .b-interview, .b-offer, .b-teams { background: var(--info-bg); color: var(--info-fg); }
  .tone-warn, .b-warn,
  .b-pending_approval, .b-on_hold, .b-soon { background: var(--warn-bg); color: var(--warn-fg); }
  /* "Needs you": the one gold accent for items waiting on the viewer (dashboard queue rows, unread counts, 'Ikke
     bekreftet', the medium risk band). Not a status tone: a status keeps its own colour everywhere, so mark the item
     tone-gold explicitly instead of re-colouring tone-warn. 5.69:1. */
  .tone-gold, .b-attn { background: var(--gold-soft); color: var(--gold-ink); }
  .tone-danger, .b-bad, .b-danger,
  .b-overdue, .b-lost, .b-rejected, .b-expired, .b-no_show, .b-not_qualified, .b-not_accepted, .b-declined,
  .b-disputed { background: var(--danger-bg); color: var(--danger-fg); }
  .tone-neutral, .b-neutral,
  .b-draft, .b-locked, .b-invoiced, .b-credited, .b-cancelled, .b-completed, .b-inactive, .b-archived,
  .b-not_required, .b-withdrawn, .b-terminated { background: var(--neutral-bg); color: var(--neutral-fg); }
  .badge.solid.tone-danger, .b-critical { background: var(--danger); color: var(--on-danger); }   /* only 'Kritisk' is solid */
  /* Category badges (not statuses): timesheet rate types and task priority */
  .badge.r-dag { background: var(--neutral-bg); color: var(--neutral-fg); }
  .badge.r-kveld { background: var(--info-bg); color: var(--info-fg); }
  .badge.r-natt { background: var(--rate-natt-bg); color: var(--rate-natt-fg); }
  .badge.r-helg { background: var(--warn-bg); color: var(--warn-fg); }
  .badge.r-hd { background: var(--rate-hd-bg); color: var(--rate-hd-fg); }
  .badge.r-ot { background: var(--danger-bg); color: var(--danger-fg); }
  .p-hoy { background: var(--danger-bg); color: var(--danger-fg); }
  .p-normal { background: var(--info-bg); color: var(--info-fg); }
  .p-lav { background: var(--neutral-bg); color: var(--neutral-fg); }

  /* Utilities */
  .muted { color: var(--muted); }
  .right { text-align: right; }
  .nowrap { white-space: nowrap; }
  .hl { box-shadow: inset 0 -.26em 0 var(--gold); -webkit-box-decoration-break: clone; box-decoration-break: clone; }
  .sr-only { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden;
    clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
  .skip { position: absolute; left: -999px; top: 0; z-index: 100; padding: 10px 14px; border-radius: 0 0 8px 0;
    background: var(--brand); color: var(--on-brand); font-weight: 700; text-decoration: none; }
  .skip:focus { left: 0; color: var(--on-brand); }
  [role=button] { cursor: pointer; }
  .print-only { display: none; }   /* shown only on paper (see the print layer) */

  /* Date and time fields (v6: MF.dateField in mediflora-ui.js). The page's own <input type=date|time|datetime-local|month>
     stays in the DOM as the value holder, hidden (input[data-mf-dt]); the <mf-date> right after it is what the reader
     sees: a text field in the reader's language with a calendar button, the format for screen readers and its own error
     line. The picker (.mf-dtp) opens in the top layer (popover), so no dialog clips it. The few !important ones below
     are layout the field needs whatever a page's own (unlayered) input rules say: the hidden input, the room for the
     calendar button. */
  input[data-mf-dt] { display: none !important; }
  mf-date { position: relative; display: flex; flex-direction: column; width: 100%; min-width: 0; max-width: 100%; }
  mf-date.mf-dt-inline { display: inline-flex; vertical-align: middle; }
  mf-date[hidden] { display: none !important; }
  .mf-dt-row { display: flex; gap: 8px; min-width: 0; }
  .mf-dt-box { position: relative; display: flex; flex: 1 1 auto; min-width: 0; }
  .mf-dt-datetime .mf-dt-tbox { flex: 0 1 7.5em; }
  .mf-dt-in { flex: 1 1 auto; width: 100%; min-width: 0; font-variant-numeric: tabular-nums; }
  .mf-dt-dbox > .mf-dt-in { padding-inline-end: 46px !important; }
  .mf-dt-btn { position: absolute; top: 0; right: 0; bottom: 0; width: 44px; display: flex; align-items: center;
    justify-content: center; margin: 0; padding: 0; border: 0; border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
    background: transparent; color: var(--muted); cursor: pointer; -webkit-tap-highlight-color: transparent; }
  .mf-dt-btn:not(:disabled):hover, .mf-dt-btn[aria-expanded="true"] { color: var(--brand); }
  .mf-dt-btn:focus-visible { outline: 3px solid var(--focus); outline-offset: -4px; }
  .mf-dt-btn:disabled { cursor: not-allowed; opacity: .5; }
  .mf-dt-btn svg { width: 20px; height: 20px; }
  .mf-dt-err { display: flex; align-items: flex-start; gap: 6px; margin: 6px 0 0; font-size: var(--fs-xs); line-height: 1.45;
    font-weight: 600; color: var(--danger); }
  .mf-dt-err:empty { margin: 0; }
  .mf-dt-err > svg { width: 14px; height: 14px; margin-top: 2px; flex-shrink: 0; }
  /* The picker: 44px days (they share the width on the narrowest phones), today ringed, the chosen day filled, days
     outside min / max struck through. Its own font: it may sit inside a bold label. */
  .mf-dtp { position: fixed; inset: auto; margin: 0; z-index: var(--z-toast); box-sizing: border-box; width: 332px;
    max-width: calc(100vw - 16px); padding: 10px; border: 1px solid var(--line-strong); border-radius: var(--radius);
    background: var(--surface); color: var(--ink); box-shadow: var(--shadow-lg); overflow: auto; cursor: default;
    font: 400 15px/1.3 var(--font-body); letter-spacing: normal; text-align: left; text-transform: none; white-space: normal; }
  .mf-dtp.mf-dtp-nopop { display: none; }
  .mf-dtp.mf-dtp-nopop.open { display: block; }
  .mf-dtp-head { display: flex; align-items: center; gap: 4px; margin-bottom: 4px; }
  .mf-dtp-title { flex: 1 1 auto; min-width: 0; text-align: center; font-family: var(--font-head); font-size: 15px; font-weight: 600; }
  .mf-dtp-nav { flex: 0 0 44px; width: 44px; height: 44px; display: inline-flex; align-items: center; justify-content: center;
    margin: 0; padding: 0; border: 0; border-radius: var(--radius-sm); background: transparent; color: var(--ink); cursor: pointer; }
  .mf-dtp-nav:not(:disabled):hover { background: var(--chip); }
  .mf-dtp-nav:disabled { color: var(--muted); opacity: .4; cursor: not-allowed; }
  .mf-dtp-nav svg { width: 20px; height: 20px; }
  .mf-dtp-row { display: flex; }
  .mf-dtp-row > * { flex: 1 1 0; min-width: 0; height: 44px; display: flex; align-items: center; justify-content: center; }
  .mf-dtp-wds > * { height: 30px; font-size: var(--fs-xs); font-weight: 600; color: var(--muted); }
  .mf-dtp-day { border-radius: var(--radius-sm); cursor: pointer; font-variant-numeric: tabular-nums; user-select: none;
    -webkit-tap-highlight-color: transparent; }
  .mf-dtp-day:hover { background: var(--chip); }
  .mf-dtp-day[aria-current="date"] { font-weight: 700; box-shadow: inset 0 0 0 1.5px var(--muted); }
  .mf-dtp-day[aria-selected="true"] { background: var(--brand); color: var(--on-brand); font-weight: 700; box-shadow: none; }
  .mf-dtp-day[aria-disabled="true"] { background: none; color: var(--muted); opacity: .5; text-decoration: line-through; cursor: not-allowed; }
  .mf-dtp-day:focus { outline: none; }
  .mf-dtp-day:focus-visible { outline: 3px solid var(--focus); outline-offset: -3px; }
  /* On the chosen (filled) day the ring would sit on the fill, near its colour: a band of the surface between them. */
  .mf-dtp-day[aria-selected="true"]:focus-visible { box-shadow: inset 0 0 0 5px var(--surface); }
  .mf-dtp-foot { display: flex; justify-content: space-between; gap: 8px; margin-top: 6px; }
  .mf-dtp-act { min-height: 44px; padding: 0 14px; border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
    background: var(--surface); color: var(--ink); font: inherit; font-size: 14px; font-weight: 700; cursor: pointer; }
  .mf-dtp-act:not(:disabled):hover { background: var(--chip); }
  .mf-dtp-act:disabled { opacity: .5; cursor: not-allowed; }
  /* The month picker (a month field): the year in the head, its twelve months in four rows of three, a little apart. */
  .mf-dtp-mons { display: flex; flex-direction: column; gap: 4px; margin-top: 2px; }
  .mf-dtp-mons > .mf-dtp-row { gap: 4px; }
  .mf-dtp-mons .mf-dtp-row > * { height: 48px; }
  .mf-dtp-mon { white-space: nowrap; }
  /* High contrast: no shadows, so today is underlined (never an outline — that is the focus ring's), the focus ring is
     CanvasText, and on the chosen day (Highlight) it is HighlightText. */
  @media (forced-colors: active) {
    .mf-dtp-day[aria-current="date"] { text-decoration-line: underline; text-decoration-thickness: 2px; text-underline-offset: 4px; }
    .mf-dtp-day[aria-current="date"][aria-disabled="true"] { text-decoration-line: underline line-through; }
    .mf-dtp-day:focus-visible { outline: 3px solid CanvasText; outline-offset: -3px; }
    .mf-dtp-day[aria-selected="true"] { forced-color-adjust: none; background: Highlight; color: HighlightText; box-shadow: none; }
    .mf-dtp-day[aria-selected="true"]:focus-visible { outline-color: HighlightText; box-shadow: none; }
  }

  /* Chip picker (v7; MF.pick in mediflora-ui.js). A field-like box: the chosen values as removable chips (.mf-tag), then
     one row of a search icon, the search field (a combobox) and the chevron — they wrap together, so the chevron never
     sits alone on a line. Its list (.mf-pick-list, a listbox) opens UNDER the box
     in the page flow, so no dialog or sheet clips it; groups have sticky headings with a count of what is chosen in
     them; the active option (aria-activedescendant — the focus stays in the field) has a ring. .is-off = disabled
     (chips greyed, no × ). Quick chips above the box are .mf-tog.sm. The !important ones keep the search field bare
     whatever a page's own (unlayered) input rules say: the box draws the border and the focus ring. */
  .mf-pick { position: relative; display: flex; flex-direction: column; gap: 8px; min-width: 0; }
  .mf-pick-quick { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
  .mf-pick-ql { margin-right: 2px; font-size: var(--fs-xs); font-weight: 600; color: var(--muted); }
  .mf-pick-box { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; min-width: 0; min-height: 44px; padding: 5px 4px 5px 10px;
    border: 1px solid var(--line-strong); border-radius: var(--radius-sm); background: var(--surface); cursor: text;
    transition: border-color .15s, box-shadow .15s; }
  .mf-pick-box:hover { border-color: var(--line-hover); }
  .mf-pick-box:focus-within { border-color: var(--brand); box-shadow: var(--focus-ring); }
  .mf-pick-inw { display: flex; align-items: center; gap: 6px; flex: 1 1 13em; min-width: 11em; }   /* icon, field and chevron: one row */
  .mf-pick-ic { display: inline-flex; flex-shrink: 0; color: var(--muted); }
  .mf-pick-ic svg { width: 16px; height: 16px; }
  .mf-pick-tags { display: flex; flex-wrap: wrap; gap: 6px; min-width: 0; max-width: 100%; margin: 0; padding: 0; list-style: none; }
  .mf-pick-tags:empty { display: none; }
  .mf-tag { display: inline-flex; align-items: center; gap: 2px; min-width: 0; max-width: 100%; min-height: 30px; margin: 0;
    padding: 2px 2px 2px 11px; border-radius: 999px; background: var(--brand-soft); color: var(--brand-dark);
    font-size: var(--fs-sm); font-weight: 600; line-height: 1.3; }
  .mf-tag-l { min-width: 0; overflow-wrap: anywhere; }
  .mf-tag-x { display: grid; place-items: center; flex-shrink: 0; width: 26px; height: 26px; margin: 0; padding: 0; border: 0;
    border-radius: 50%; background: none; color: var(--brand); cursor: pointer; }
  .mf-tag-x:hover { background: var(--chip-hover); color: var(--danger); }
  .mf-tag-x:focus-visible { outline: 2px solid var(--focus); outline-offset: 0; }
  .mf-tag-x svg { width: 14px; height: 14px; }
  .mf-pick-in { flex: 1 1 auto; width: auto !important; min-width: 0; height: auto !important; min-height: 32px !important; margin: 0;
    padding: 4px 2px !important; border: 0 !important; border-radius: 0 !important; background: transparent !important;
    box-shadow: none !important; outline: 0; color: var(--ink); }
  .mf-pick-in:focus { box-shadow: none !important; outline: 0; }
  .mf-pick-in:disabled { background: transparent !important; cursor: not-allowed; }
  .mf-pick-tg { display: grid; place-items: center; flex-shrink: 0; width: 34px; height: 34px; margin: 0; padding: 0;
    border: 0; border-radius: 8px; background: none; color: var(--muted); cursor: pointer; }
  .mf-pick-tg:hover:not(:disabled) { background: var(--chip); color: var(--ink); }
  .mf-pick-tg:disabled { cursor: not-allowed; opacity: .5; }
  .mf-pick-tg svg { width: 18px; height: 18px; transition: transform .15s; }
  .mf-pick-tg[aria-expanded="true"] svg { transform: rotate(180deg); }
  .mf-pick-list { max-height: 288px; overflow: auto; overscroll-behavior: contain; padding: 4px; border: 1px solid var(--line);
    border-radius: 12px; background: var(--surface); box-shadow: var(--sheet-shadow); }
  .mf-pick-list[hidden], .mf-pick-none[hidden] { display: none; }
  .mf-pick-grp + .mf-pick-grp, .mf-pick-grp + .mf-pick-opt { margin-top: 2px; }
  .mf-pick-gh { position: sticky; top: -4px; z-index: 1; display: flex; align-items: center; gap: 8px; margin: 0 -4px; padding: 10px 14px 5px;
    background: var(--surface); font-size: 11.5px; font-weight: 700; letter-spacing: .6px; text-transform: uppercase; color: var(--muted); }
  .mf-pick-gn { min-width: 20px; padding: 0 6px; border-radius: 999px; background: var(--brand-soft); color: var(--brand-dark);
    font-size: 11px; line-height: 18px; text-align: center; letter-spacing: 0; }
  .mf-pick-opt { display: flex; align-items: center; gap: 10px; min-height: 40px; padding: 8px 10px; border-radius: 8px; color: var(--ink);
    font-size: 14.5px; line-height: 1.3; cursor: pointer; user-select: none; -webkit-tap-highlight-color: transparent; }
  .mf-pick-opt:hover { background: var(--hover-soft); }
  .mf-pick-opt.act { background: var(--brand-soft); box-shadow: inset 0 0 0 2px var(--focus); }
  .mf-pick-ck { display: grid; place-items: center; flex-shrink: 0; width: 18px; height: 18px; border: 1.5px solid var(--line-hover);
    border-radius: 5px; background: var(--surface); color: transparent; }
  .mf-pick-ck svg { width: 13px; height: 13px; }
  .mf-pick-opt[aria-selected="true"] .mf-pick-ck { border-color: var(--brand-dark); background: var(--brand-dark); color: var(--on-brand); }
  .mf-pick-opt[aria-selected="true"] .mf-pick-ol { font-weight: 700; }
  .mf-pick-ol { min-width: 0; overflow-wrap: anywhere; }
  .mf-pick-add { color: var(--brand); font-weight: 700; }
  .mf-pick-add .mf-pick-ck { border-color: transparent; background: var(--brand-soft); color: var(--brand); }
  .mf-pick-none { margin: 0; padding: 2px; font-size: var(--fs-sm); color: var(--muted); }
  .mf-pick.is-off .mf-pick-box { border-color: var(--line); background: var(--bg); box-shadow: none; cursor: not-allowed; }
  .mf-pick.is-off .mf-pick-box:hover { border-color: var(--line); }
  .mf-pick.is-off .mf-tag { padding-right: 11px; background: var(--chip); color: var(--muted); text-decoration: line-through; text-decoration-color: var(--line-hover); }
  .mf-pick.is-off .mf-tag-x { display: none; }
  /* A count beside a field label («3 valgt»): a quiet pill, gone at 0. */
  .mf-count { display: inline-flex; align-items: center; padding: 0 9px; border-radius: 999px; background: var(--brand-soft);
    color: var(--brand-dark); font-size: 12px; font-weight: 700; line-height: 20px; white-space: nowrap; }
  .mf-count:empty, .mf-count[hidden] { display: none; }
  /* Toggle pills (MF.toggles; also the quick chips of MF.pick): aria-pressed toggles — on = filled --brand-dark with a
     check —, or (.mf-togs-one) role=radio + aria-checked in a radiogroup, drawn as radio pills: a round dot, on = a filled
     dot (a ring of the surface inside) on --brand-soft with a --brand-dark edge, so a single choice never looks like the
     toggles. The state is never colour alone. .mf-togs-clr = the quiet «Fjern valg» after the radios. .sm = 32px. */
  .mf-togs { display: flex; flex-wrap: wrap; gap: 8px; }
  .mf-tog { display: inline-flex; align-items: center; justify-content: center; gap: 6px; min-height: 40px; margin: 0; padding: 7px 16px;
    border: 1px solid var(--line-strong); border-radius: 999px; background: var(--surface); color: var(--ink);
    font: inherit; font-size: 14.5px; font-weight: 600; line-height: 1.25; cursor: pointer; transition: background-color .12s, border-color .12s; }
  .mf-tog:hover:not(:disabled) { border-color: var(--brand); }
  .mf-tog:is([aria-pressed="true"], [aria-checked="true"]) { border-color: var(--brand-dark); background: var(--brand-dark); color: var(--on-brand); }
  .mf-tog-ck { display: none; }
  .mf-tog:is([aria-pressed="true"], [aria-checked="true"]) .mf-tog-ck { display: inline-flex; }
  .mf-tog-ck svg { width: 15px; height: 15px; }
  .mf-tog:disabled { opacity: .5; cursor: not-allowed; }
  .mf-tog.sm { min-height: 32px; padding: 4px 12px; font-size: var(--fs-sm); }
  .mf-togs-has-clr { align-items: center; column-gap: 14px; }
  .mf-togs-g { display: flex; flex-wrap: wrap; gap: 8px; min-width: 0; }
  .mf-togs-one .mf-tog { padding-left: 13px; }
  .mf-tog-rd { flex-shrink: 0; width: 16px; height: 16px; border: 1.5px solid var(--line-hover); border-radius: 50%; background: var(--surface); }
  .mf-togs-one .mf-tog[aria-checked="true"] { border-color: var(--brand-dark); background: var(--brand-soft); color: var(--brand-dark);
    box-shadow: inset 0 0 0 1px var(--brand-dark); }
  .mf-togs-one .mf-tog[aria-checked="true"] .mf-tog-rd { border-color: var(--brand-dark); background: var(--brand-dark); box-shadow: inset 0 0 0 3px var(--surface); }
  .mf-togs-clr { min-height: 40px; margin: 0; padding: 0 4px; border: 0; background: none; color: var(--brand); font: inherit;
    font-size: var(--fs-sm); font-weight: 600; text-decoration: underline; text-underline-offset: 3px; cursor: pointer; }
  .mf-togs-clr:hover:not(:disabled) { color: var(--brand-dark); }
  .mf-togs-clr:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; border-radius: 6px; }
  .mf-togs-clr:disabled { opacity: .5; cursor: not-allowed; }
  .mf-togs-clr[hidden] { display: none; }
  @media screen and (max-width: 820px) {
    .mf-tog, .mf-tog.sm, .mf-togs-clr { min-height: 44px; }
    .mf-tag { min-height: 36px; }
    .mf-tag-x { width: 32px; height: 32px; }
    .mf-pick-opt { min-height: 44px; }
    .mf-pick-tg { width: 40px; height: 40px; }
    .mf-pick-in { font-size: 16px; }
  }
  @media (forced-colors: active) {
    .mf-pick-opt.act { outline: 2px solid Highlight; outline-offset: -2px; }
    .mf-tog:is([aria-pressed="true"], [aria-checked="true"]), .mf-pick-opt[aria-selected="true"] .mf-pick-ck { forced-color-adjust: none; background: Highlight; color: HighlightText; }
    .mf-tog-rd { border-color: ButtonText; }
    .mf-togs-one .mf-tog[aria-checked="true"] .mf-tog-rd { forced-color-adjust: none; border-color: HighlightText; background: HighlightText; box-shadow: inset 0 0 0 3px Highlight; }
  }
  @media (prefers-reduced-motion: reduce) { .mf-pick-tg svg { transition: none; } }

  /* The availability week grid (MF.weekGrid, wave E · T1): a day column and three equal part-of-day columns (+ an optional
     narrow action column), every cell a 44px button with its state as an icon + a word on a tone: Ledig = ok, Opptatt = the
     neutral chip, Hovedjobb = info, Ikke bekreftet (stale) = warn, Pause / Oppdrag / Booket = gold. A cell from the weekly
     pattern has a dashed edge (data-src="pattern"); nothing filled in is a quiet dash. The state is never colour alone. On a
     phone (375 px) the words shrink, never the 44px target; there is no horizontal scroll. */
  .mf-wk { display: grid; gap: 6px; }
  .mf-wk-row { display: grid; grid-template-columns: minmax(58px, 1fr) repeat(3, minmax(0, 1.3fr)); align-items: center; gap: 6px; }
  .mf-wk-ra .mf-wk-row { grid-template-columns: minmax(58px, 1fr) repeat(3, minmax(0, 1.3fr)) 36px; }
  .mf-wk-head { font-size: 12px; font-weight: 700; letter-spacing: .03em; text-transform: uppercase; color: var(--muted); text-align: center; }
  .mf-wk-day { display: flex; flex-direction: column; align-items: flex-start; gap: 1px; min-width: 0; font-size: var(--fs-sm); line-height: 1.2; text-align: left; }
  .mf-wk-day b { font-weight: 700; color: var(--ink); }
  .mf-wk-day > span { color: var(--muted); font-size: 12.5px; }
  .mf-wk-row.is-today .mf-wk-day b { color: var(--brand); }
  .mf-wk-row.is-today .mf-wk-day > span:first-of-type::after { content: " •"; color: var(--brand); }
  .mf-wk-badge { margin-top: 2px; padding: 0 6px; border-radius: 999px; font-size: 11px; font-weight: 700; line-height: 18px; white-space: nowrap; }
  .mf-wk-c { display: flex; align-items: center; justify-content: center; gap: 4px; width: 100%; min-width: 0; min-height: 44px; margin: 0;
    padding: 4px 6px; border: 1px solid var(--line); border-radius: 10px; background: var(--surface); color: var(--muted);
    font: inherit; font-size: 13.5px; font-weight: 600; line-height: 1.15; cursor: pointer; transition: background-color .12s, border-color .12s; }
  .mf-wk-c:hover:not([aria-disabled="true"]) { border-color: var(--brand); }
  .mf-wk-c:focus-visible, .mf-wk-ra-b:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
  .mf-wk-c[aria-disabled="true"] { cursor: default; }
  .mf-wk-t { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .mf-wk-ic { display: inline-flex; flex-shrink: 0; }
  .mf-wk-ic svg { width: 15px; height: 15px; }
  .mf-wk-c[data-st="ledig"] { border-color: var(--ok-fg); background: var(--ok-bg); color: var(--ok-fg); }
  .mf-wk-c[data-st="opptatt"] { border-color: var(--line-strong); background: var(--chip); color: var(--ink); }
  .mf-wk-c[data-st="hovedjobb"] { border-color: var(--info-fg); background: var(--info-bg); color: var(--info-fg); }
  .mf-wk-c[data-st="stale"] { border-color: var(--warn-fg); background: var(--warn-bg); color: var(--warn-fg); }
  .mf-wk-c:is([data-st="pause"], [data-st="oppdrag"], [data-st="booket"]) { border-color: var(--gold-ink); background: var(--gold-soft); color: var(--gold-ink); }
  .mf-wk-c[data-src="pattern"] { border-style: dashed; border-width: 1.5px; }
  .mf-wk-c[data-st="ukjent"] .mf-wk-ic { display: none; }   /* an empty cell is one quiet dash (its text), not a dash icon + a dash */
  .mf-wk-c[data-st="ukjent"] { color: var(--muted); }
  .mf-wk-ra-b { display: inline-flex; align-items: center; justify-content: center; width: 36px; height: 44px; margin: 0; padding: 0;
    border: 0; border-radius: 8px; background: none; color: var(--muted); cursor: pointer; }
  .mf-wk-ra-b:hover { background: var(--chip); color: var(--ink); }
  /* The legend under a grid: the same chips, small, not buttons. */
  .mf-wk-legend { display: flex; flex-wrap: wrap; gap: 6px 14px; margin: 10px 0 0; padding: 0; list-style: none; font-size: 12.5px; color: var(--muted); }
  .mf-wk-legend li { display: inline-flex; align-items: center; gap: 6px; }
  .mf-wk-legend .mf-wk-c { width: auto; min-width: 26px; min-height: 22px; padding: 0 6px; border-radius: 6px; font-size: 12px; cursor: default; }
  @media screen and (max-width: 420px) {
    .mf-wk, .mf-wk-row { gap: 4px; }
    .mf-wk-row { grid-template-columns: minmax(52px, .9fr) repeat(3, minmax(0, 1.3fr)); }
    .mf-wk-ra .mf-wk-row { grid-template-columns: minmax(52px, .9fr) repeat(3, minmax(0, 1.3fr)) 32px; }
    .mf-wk-c { gap: 3px; padding: 4px 3px; font-size: 12.5px; }
    .mf-wk-ra-b { width: 32px; }
  }
  @media screen and (max-width: 360px) { .mf-wk-c .mf-wk-ic { display: none; } }
  @media (forced-colors: active) {
    .mf-wk-c { border-color: ButtonText; }
    .mf-wk-c[data-st="ledig"] { forced-color-adjust: none; background: Highlight; color: HighlightText; }
  }
}

/* ── 4. Print ────────────────────────────────────────────────────────────────────────────────────────────
   Any portal page prints as a clean document: the app chrome goes (sidebars, top and phone bars, breadcrumbs, menus,
   tabs, filters, toasts, help tips, and every .btn unless it is .print-keep), the content takes the full width, text
   is black on white, cards lose shadow and fill, and cards, table rows, KPI strips, charts and signature blocks do
   not split across pages; table headers repeat. Links print as their text (no URL after them). Hide anything else
   with .no-print; show print-only extras (a document header on a list page) with .print-only.
   The chrome rules use !important on purpose: each portal's own (unlayered) rules would otherwise win, including its
   phone rules — an A4 page is ~700px wide, so every @media (max-width: 820px) rule in the portals also matches on
   paper (the shared layer's own phone rules are screen-only since v4). */
@layer mf.print {
  @media print {
    :root, [data-theme] {
      color-scheme: light;
      --bg: #fff; --surface: #fff; --ink: #000; --muted: #3b3b3b; --placeholder: #555;
      --line: #bdbdbd; --line-soft: #d6d6d6; --line-strong: #8c8c8c; --line-hover: #8c8c8c;
      --chip: #fff; --chip-hover: #fff; --brand: #000; --brand-dark: #000; --brand-soft: #fff; --accent: #000;
      --gold-soft: #fff; --gold-ink: #000; --on-brand: #000; --on-danger: #000; --on-ok: #000;
      --ok-bg: #fff; --ok-fg: #000; --info-bg: #fff; --info-fg: #000; --warn-bg: #fff; --warn-fg: #000;
      --danger-bg: #fff; --danger-fg: #000; --neutral-bg: #fff; --neutral-fg: #000; --crit-bg: #fff;
      --shadow: none; --shadow-lg: none; --sheet-shadow: none; --tip-shadow: none; --skel: #eee;
      --chart-bar: #8f8f8f; --chart-bar-hover: #8f8f8f; --chart-neg: #cfcfcf; --chart-neg-hover: #cfcfcf;
      --chart-part-bg: #fff; --chart-part-line: #000; --chart-grid: #dcdcdc; --chart-zero: #000;
    }
    html, body { background: #fff !important; color: #000 !important; }
    body { display: block !important; min-height: 0 !important; }
    /* App chrome and controls */
    .side, .mbar, .scrim, .topbar, .crumbs, .breadcrumbs, header.pub, footer.pub, .skip, .toast, .ihint, .ihint-tip,
    .langmenu, .langlist, .umenu, .upop, .backlink, .thread-back, .replybar, .typing-ind, .filterbar, .tabs, .ptabs,
    .seg[role="group"], [role="menu"], [role="tooltip"], button[aria-haspopup], .dlg-x, .dlg-actions, .pf-actions,
    .merge-chips, .pv-tools, .mfc-foot, .mfc-tip, .no-print, .btn:not(.print-keep) { display: none !important; }
    .print-only { display: block !important; }
    /* Content: the full width of the page */
    .content, main, #app, #root, .app, .app main { width: auto !important; max-width: none !important; margin: 0 !important;
      padding: 0 !important; overflow: visible !important; }
    /* Flat: no shadow, no fill; a hairline keeps a card together */
    *:not(.mfc-bar), *::before, *::after { box-shadow: none !important; text-shadow: none !important; }   /* the running period keeps its outline */
    .panel, .kstrip, .inbox, .preview-frame, .skel-card { background: #fff !important; border-color: var(--line) !important; }
    .panel { padding: 12px 14px; }
    .badge, .chip, .tabn { background: none !important; color: #000 !important; border: 1px solid #8c8c8c; }
    a, .lnk { color: inherit !important; text-decoration: none !important; }
    a[href]::after { content: none !important; }
    button { color: inherit; }
    /* Page breaks */
    h1, h2, h3, h4, .panel-head, .panelhead, .pd-head { break-after: avoid; }
    p, li, dd { orphans: 3; widows: 3; }
    .panel, .kstrip, .kcell, tr, .recsteps, .mfc, figure, .empty, .sig-block, .pd-head, dl.facts, .bubble, .cal-chip { break-inside: avoid; }
    thead { display: table-header-group; }
    tfoot { display: table-footer-group; }
    /* Charts keep their bars on paper (grey, the running period as an outline) */
    .mfc-bar, .mfc-meter, .mfc-meter::after { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
    .mfc-frame[hidden] { display: block !important; }   /* the picture prints even if the table view was on */
    .mfc-table { display: none !important; }
    .mfc.is-busy .mfc-frame { opacity: 1; }
    [data-tone="danger"] { --mfc-tone: #262626; } [data-tone="warn"] { --mfc-tone: #666; } [data-tone="neutral"] { --mfc-tone: #b5b5b5; }
    [data-tone="ok"], [data-tone="info"], [data-tone="brand"] { --mfc-tone: #555; } [data-tone="gold"] { --mfc-tone: var(--chart-bar); }
    /* The document sheet becomes the page */
    .print-doc { max-width: none; margin: 0; padding: 0; border: 0; border-radius: 0; }
    .pd-head { border-bottom-color: #000; }
  }
}

/* Paper: A4 margins and a page number ("2 / 5", no words, so it needs no translation) in the bottom-right margin box
   (Chrome / Edge 131+; other browsers print without it). Outside the layers so a page can restate @page if it must. */
@page { margin: 16mm 14mm 18mm; }
@page { @bottom-right { content: counter(page) " / " counter(pages); font: 9pt 'Source Sans 3', 'Segoe UI', sans-serif; color: #444; } }
