:root {
    /* Match old app's palette (see fipo-frontend/src/assets/css/theme/standard.css). */
    --bg: #f8f8f8;
    --surface: #fff;
    --surface-2: #fafafa;
    --fg: #4a4a4a;
    /* 2026-04-24: bumpet fra #9a9a9a (2.9:1 — failed WCAG AA) → #6b6b6b
       (5.20:1 — AA solid). Brukt som sekundær tekst: sidebar-headings,
       nav-items, field-labels, inquery-body. Se docs/design.md §Contrast. */
    --muted: #6b6b6b;
    --border: #e7e7e7;
    /* 2026-04-24: nytt token for actionable UI-borders (inputs, selects,
       textareas, btn-ghost). Må passere WCAG 1.4.11 (3:1 mot surface).
       `--border` (#e7e7e7, 1.22:1) er OK for dekorative kort-kanter, men
       for kontroller brukeren skal klikke trenger vi 3:1 for å møte AA.
       #8a8a8a gir 3.38:1 mot hvit → solid AA. */
    --border-strong: #8a8a8a;
    --link: #3696fc;
    --link-hover: #235bb0;
    --accent: #3696fc;
    /* Solid-button hover: separate from --link-hover (which exists to
       darken in light mode and lighten in dark mode for *text* links).
       Buttons have white text and need DARKER bg in both modes so the
       label stays readable. */
    --btn-primary-hover: #235bb0;
    --danger: #e52320;
    --success: #10b981;

    /* Function-icon palette — see docs/design.md §Colored function icons */
    --icon-blue: #3696fc;        --icon-blue-soft: rgba(54, 150, 252, 0.12);
    --icon-green: #10b981;       --icon-green-soft: rgba(16, 185, 129, 0.14);
    --icon-amber: #f59e0b;       --icon-amber-soft: rgba(245, 158, 11, 0.15);
    --icon-purple: #8b5cf6;      --icon-purple-soft: rgba(139, 92, 246, 0.14);
    --icon-red: #ef4444;         --icon-red-soft: rgba(239, 68, 68, 0.12);  --icon-red-line: rgba(239, 68, 68, 0.4);
    --shade-1: #f8f9fc;
    --shade-2: #f2f2f2;
    /* Code-block surface — used by `.token-value` for OAuth/secret display
       on /agent/settings/integrations. Distinct from `--shade-2` (which
       is for inline `<code>` and dense table stripes) — code blocks need
       higher contrast since they hold copy-paste-critical content. */
    --code-bg: #1f2329;
    --code-fg: #e5e7eb;
    /* Logo backdrop — third-party brand logos (Microsoft 365, AI Gateway,
       CMDB) are designed for white-on-white. We keep the backdrop white
       in BOTH themes so logos render as their vendor expects. Used on
       `.integration-tile-logo` + `.integration-detail-logo`. Don't reuse
       this token elsewhere — logos are the only legitimate "white in
       dark mode" surface. */
    --logo-backdrop: #fff;
    /* Brand colors — third-party identity, kept identical in both themes
       so badges/chips render in the vendor's recognised hue. Add new
       brands here as `--<vendor>-blue` etc. only when there's a
       second use-site; one-off brand-mentions can stay hardcoded
       inline-CSS-property. */
    --ms-blue: #0078d4;
    --radius: 6px;
    --radius-lg: 10px;
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.04);
    --shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
    --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;

    /* Content widths — see docs/design.md §Content widths. */
    --content-narrow: 700px;   /* fokusert: enkle skjemaer, profil-sider */
    --content-default: 900px;  /* standard: settings landing, innstillinger-undersider */
    --content-wide: 1400px;    /* dense data: ticket list, rapporter */
}

/* ------ Dark mode ------
   Token override. Every view is expected to use `var(--surface)` /
   `var(--fg)` / etc. — no hard-coded #fff / #000 — so switching
   `<html data-theme="dark">` re-skins the whole app.
   Toggle via `helpers/theme.js`; persists in localStorage. */
:root[data-theme="dark"] {
    --bg: #161619;
    --surface: #1e1e22;
    --surface-2: #2a2a30;
    --fg: #e5e5e7;
    --muted: #8a8a92;
    --border: #2e2e34;
    --link: #66b2ff;
    --link-hover: #a3cdff;
    --accent: #4ba4ff;
    /* Darker than --accent so white button-text stays readable on hover.
       #1d68bd vs #ffffff = 4.7:1 (passes WCAG AA for normal text). */
    --btn-primary-hover: #1d68bd;
    --danger: #ef5350;
    --success: #34d399;

    /* Icon colours stay saturated (they carry meaning); soft-tints stay
       as rgba() — their alpha sits well on the darker background too. */
    --icon-blue: #4ba4ff;        --icon-blue-soft: rgba(75, 164, 255, 0.18);
    --icon-green: #34d399;       --icon-green-soft: rgba(52, 211, 153, 0.18);
    --icon-amber: #fbbf24;       --icon-amber-soft: rgba(251, 191, 36, 0.20);
    --icon-purple: #a78bfa;      --icon-purple-soft: rgba(167, 139, 250, 0.20);
    --icon-red: #f87171;         --icon-red-soft: rgba(248, 113, 113, 0.20);  --icon-red-line: rgba(248, 113, 113, 0.45);

    --shade-1: #26262b;   /* hover-bg */
    --shade-2: #2a2a30;   /* deeper shade for stripes / dense tables */
    /* Code-block surface — slightly lighter than --bg/--surface so the
       block reads as "elevated" against dark surrounds. */
    --code-bg: #2d333b;
    --code-fg: #e5e7eb;
    /* `--logo-backdrop` stays white in dark mode by design — see comment
       in light-mode :root. Vendor-logo expectation overrides theme. */
    --logo-backdrop: #fff;
    /* `--ms-blue` stays the brand value across themes — same rationale
       as logo-backdrop. */
    --ms-blue: #0078d4;
    /* Dark-mode input-border: 3.21:1 mot #1e1e22 (AA). */
    --border-strong: #6a6a70;

    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.55);
    --shadow: 0 2px 8px rgba(0, 0, 0, 0.6);
}

/* Images can look harsh on a dark surface; tone them slightly.
   Applies to raster photos (avatars, attachment thumbs). */
:root[data-theme="dark"] img { filter: brightness(0.95); }

* { box-sizing: border-box; }

/* HTML `hidden` attribute is UA-styled to `display: none`, but any
   class that sets `display: flex|grid|block|…` wins due to specificity.
   Restore the intent globally so `<div class="x" hidden>` always
   disappears, regardless of what `.x` does.
   (Historical example: .nav-badge + .notifications-dropdown both had
   their own display rules that silently overrode `hidden`.) */
[hidden] { display: none !important; }

/* Content-width utility classes. Apply to a wrapper inside the main
   content area to center at one of the standard widths. See
   docs/design.md §Content widths for when to use each. */
.content-narrow,
.content-default,
.content-wide {
    width: 100%;
    margin-left: auto;
    margin-right: auto;
}
.content-narrow  { max-width: var(--content-narrow); }
.content-default { max-width: var(--content-default); }
.content-wide    { max-width: var(--content-wide); }
html, body { margin: 0; padding: 0; }

/* ------ Subtle scrollbar utility ------
   Apply `.scroll-subtle` to any scrollable container (dropdown body,
   drawer content, long lists) to get a thin track-less scrollbar that
   only appears on hover/focus. Works on WebKit + Firefox; falls back
   to browser default if neither style spec applies. Track stays
   transparent; thumb is border-grey → muted on direct hover. */
.scroll-subtle {
    scrollbar-width: thin;
    scrollbar-color: transparent transparent;
    transition: scrollbar-color 0.15s;
}
.scroll-subtle:hover,
.scroll-subtle:focus-within {
    scrollbar-color: var(--border) transparent;
}
.scroll-subtle::-webkit-scrollbar { width: 8px; height: 8px; }
.scroll-subtle::-webkit-scrollbar-track { background: transparent; }
.scroll-subtle::-webkit-scrollbar-thumb {
    background: transparent;
    border-radius: 4px;
    border: 2px solid transparent;
    background-clip: content-box;
    transition: background 0.15s;
}
.scroll-subtle:hover::-webkit-scrollbar-thumb,
.scroll-subtle:focus-within::-webkit-scrollbar-thumb {
    background: var(--border);
    background-clip: content-box;
}
.scroll-subtle::-webkit-scrollbar-thumb:hover {
    background: var(--muted);
    background-clip: content-box;
}

/* ------ Globalt page scrollbar ------
   Side-scrollbaren bor på <html>/viewport-chromen og kan ikke skjules
   bak fixed-elementer (drawer, modaler). Vi kan derimot tone den ned
   så den slutter å konkurrere med innholdet — tynn + theme-matchet
   farge. Synlig hele tiden så den fortsatt fungerer som scroll-
   affordance, men ikke "Windows-default-blank-grå". */
html {
    scrollbar-width: thin;
    scrollbar-color: var(--border-strong) transparent;
}
html::-webkit-scrollbar { width: 12px; height: 12px; }
html::-webkit-scrollbar-track { background: transparent; }
html::-webkit-scrollbar-thumb {
    background: var(--border-strong);
    border-radius: 999px;
    border: 2px solid transparent;
    background-clip: content-box;
    transition: background 0.15s;
}
html::-webkit-scrollbar-thumb:hover {
    background: var(--muted);
    background-clip: content-box;
}

body {
    margin: 0;
    font-family: var(--font);
    color: var(--fg);
    background: var(--bg);
    line-height: 1.5;
    font-size: 15px;
}

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

/* ------ Header ------ */
#app-header {
    background: var(--surface);
    border-bottom: 1px solid var(--border);
    box-shadow: var(--shadow-sm);
}
.header-inner {
    max-width: 1200px;
    margin: 0 auto;
    padding: 0.75rem 1.25rem;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
}
.brand {
    display: inline-flex;
    align-items: center;
    line-height: 0;
}
.brand img { display: block; height: 28px; width: auto; }

/* Theme-aware brand logo: two <img> elements (light + white variants),
   one shown per theme. Both are loaded so the swap is instant when the
   user toggles theme. CSS-only — no JS swap needed. Used in both the
   user-portal topbar (.brand) and the agent shell sidebar (.agent-brand).
   Double-class selector (`.brand-logo.brand-logo-{variant}`) bumps
   specificity above `.brand img` / `.agent-brand img` (0,1,1) which
   would otherwise force display:block on both variants. */
.brand-logo.brand-logo-dark { display: none; }
:root[data-theme="dark"] .brand-logo.brand-logo-light { display: none; }
:root[data-theme="dark"] .brand-logo.brand-logo-dark { display: block; }

.header-nav {
    display: flex;
    gap: 0.25rem;
    align-items: center;
}

.nav-icon {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    padding: 0;
    border-radius: 50%;
    background: transparent;
    border: 0;
    color: var(--muted);
    font-size: 1.05rem;
    cursor: pointer;
    transition: background 0.12s, color 0.12s;
}
.nav-icon:hover { background: var(--shade-1); color: var(--accent); }
.nav-icon:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.nav-badge {
    position: absolute;
    top: 4px;
    right: 4px;
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    font-size: 0.7rem;
    font-weight: 700;
    color: #fff;
    /* Red — attention-by-design. The "red = danger" rule from design.md
       §Icons doesn't apply here: count-badges are meant to be noticed,
       not signal danger. User-tested preference vs accent-blue. */
    background: var(--icon-red);
    border-radius: 999px;
    display: flex;
    align-items: center;
    justify-content: center;
    line-height: 1;
    transform: scale(1);
}
/* (`[hidden]` global rule above handles this case now.) */

/* Pop-animasjon ved add-to-cart. Trigges av cart-badge-helperen som
   legger på `.is-bumped` på badge + parent nav-ikon, så fjerner
   selv via animationend (eller starter på nytt ved gjentatte kall).
   Hjelper brukeren å se "noe skjedde her oppe" — toasten forsvinner,
   handlekurv-ikonet gir vedvarende signal med tellingen + et kort
   pop som trekker blikket. */
.nav-badge.is-bumped { animation: cart-badge-pop 0.45s cubic-bezier(0.36, 0, 0.66, 1.6) both; }
.nav-icon.is-bumped > .svg-inline--fa,
.nav-icon.is-bumped > i { animation: cart-icon-jiggle 0.45s ease-out both; }
@keyframes cart-badge-pop {
    0%   { transform: scale(1); }
    40%  { transform: scale(1.6); }
    100% { transform: scale(1); }
}
@keyframes cart-icon-jiggle {
    0%   { transform: translateY(0) rotate(0); }
    25%  { transform: translateY(-2px) rotate(-6deg); }
    50%  { transform: translateY(0)    rotate(6deg); }
    75%  { transform: translateY(-1px) rotate(-3deg); }
    100% { transform: translateY(0)    rotate(0); }
}
@media (prefers-reduced-motion: reduce) {
    .nav-badge.is-bumped,
    .nav-icon.is-bumped > .svg-inline--fa,
    .nav-icon.is-bumped > i { animation: none; }
}

/* ------ User menu (avatar + dropdown) ------ */
.user-menu { position: relative; margin-left: 0.4rem; }
.user-menu-trigger {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.25rem 0.55rem 0.25rem 0.25rem;
    background: transparent;
    color: var(--fg);
    border: 0;
    border-radius: 999px;
    cursor: pointer;
    font-weight: 500;
    font-size: 0.95rem;
}
.user-menu-trigger:hover { background: var(--shade-1); }
.user-menu-chevron { font-size: 0.75rem; color: var(--muted); }

.avatar-sm {
    width: 32px;
    height: 32px;
    font-size: 0.78rem;
}
.avatar-xs {
    width: 24px;
    height: 24px;
    font-size: 0.65rem;
}
.avatar-lg {
    width: 56px;
    height: 56px;
    font-size: 1.25rem;
}

/* ------ User-profile drawer content ------
   Layout for the profile body rendered by views/user-profile-drawer.js.
   Sits inside a standard Drawer panel; matches the old app's user-sidebar
   visual (photo + customer + name + action-icons + labelled contact facts). */
.user-profile-head {
    display: flex;
    align-items: flex-start;
    gap: 1rem;
    padding-bottom: 1.25rem;
    margin-bottom: 1.25rem;
    border-bottom: 1px solid var(--border);
}
/* Beat the .avatar default size (36px) for the profile-drawer's hero avatar.
   Chained .avatar.user-profile-avatar wins over .avatar on specificity. Size
   only — overflow/position/img-fit/initials-fallback arves fra de globale
   .avatar-reglene lenger nede i fila. */
.avatar.user-profile-avatar {
    width: 96px;
    height: 96px;
    font-size: 1.6rem;
}
.user-profile-head-text {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    min-width: 0;
    padding-top: 0.1rem;
}
.user-profile-customer,
.user-profile-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 100%;
}
.user-profile-customer {
    font-size: 0.8rem;
    color: var(--muted);
    font-weight: 500;
}
.user-profile-name {
    font-size: 1.2rem;
    font-weight: 600;
    color: var(--fg);
    line-height: 1.2;
}
.user-profile-status {
    font-size: 0.78rem;
    margin-top: 0.1rem;
}
.user-profile-actions {
    display: flex;
    gap: 0.4rem;
    margin-top: 0.5rem;
}
.user-profile-action-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border-radius: var(--radius);
    color: var(--accent);
    text-decoration: none;
    transition: background 120ms ease;
}
.user-profile-action-icon:hover { background: var(--icon-blue-soft); }
.user-profile-action-icon i { font-size: 0.95rem; }

.user-profile-facts {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.85rem 1rem;
    margin: 0 0 1.25rem;
}
.user-profile-facts > div { display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; }
.user-profile-facts dt {
    font-size: 0.78rem;
    color: var(--muted);
    font-weight: 500;
}
.user-profile-facts dd {
    margin: 0;
    font-size: 0.95rem;
    color: var(--fg);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* Bare ekte lenker (mailto:, tel:, https:) er blå — ren tekst (Tittel,
   Avdeling, Kontor) skal være var(--fg) så bruker ikke leter etter
   click-affordance som ikke finnes. */
.user-profile-facts dd a {
    color: var(--accent);
    text-decoration: none;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    display: block;
}
.user-profile-facts dd a:hover { text-decoration: underline; }

.user-profile-section {
    border-top: 1px solid var(--border);
    padding-top: 0.85rem;
    margin-top: 1rem;
}
.user-profile-section[open] .user-profile-section-chevron {
    transform: rotate(90deg);
}
.user-profile-section-summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    cursor: pointer;
    list-style: none;
    user-select: none;
    padding: 0.25rem 0;
}
.user-profile-section-summary::-webkit-details-marker { display: none; }
.user-profile-section-chevron {
    color: var(--accent);
    font-size: 0.75rem;
    transition: transform 150ms ease;
}
.user-profile-section-body {
    margin-top: 0.6rem;
}
.user-profile-section-title {
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--accent);
    margin: 0;
}
/* Any name in the app that opens the profile drawer — comment authors,
   mentions, ticket owner, etc. Uses the cursor+hover to tell the user
   it's actionable without shouting. */
.user-link {
    cursor: pointer;
    color: inherit;
    text-decoration: none;
    border-bottom: 1px dashed transparent;
    transition: border-color 0.12s, color 0.12s;
}
.user-link:hover { color: var(--accent); border-bottom-color: var(--accent); }

/* When the entire list-item is a user-link (e.g. /agent/settings/users):
   drop the inline dashed underline — list-item has its own border + hover. */
.list-item.user-link,
.list-item.user-link:hover {
    border-bottom-style: solid;
    color: var(--fg);
}

/* ------ Confirm dialog content ------
   Used by views/confirm-dialog.js inside a standard Modal. Supports an
   optional leading icon (useful for danger/warning confirms). */
.confirm-dialog {
    display: flex;
    align-items: flex-start;
    gap: 0.85rem;
    margin-bottom: 0.25rem;
}
.confirm-dialog-icon {
    flex-shrink: 0;
    width: 40px;
    height: 40px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: var(--icon-blue-soft);
    color: var(--accent);
    font-size: 1.05rem;
}
.confirm-dialog-icon.is-danger { background: var(--icon-red-soft); color: var(--icon-red); }
.confirm-dialog-body { flex: 1; min-width: 0; }
.confirm-dialog-body p { margin: 0; color: var(--fg); font-size: 0.95rem; line-height: 1.45; }
/* Optional spam-checkbox in the reject-pending dialog. The body's <p>
   has zero margin (above), so we add top-spacing here to separate the
   sentence from the checkbox-card. */
.reject-spam-toggle { margin-top: 0.75rem; }

/* ------ Notifications bell dropdown ------
   Wired via components/notifications-bell.js. Shell lives in the topbar
   nav; uses the generic .dropdown + .dropdown-menu shell with a custom
   body block for the inbox list. */
.notifications-dropdown {
    /* Override generic dropdown-menu min-width — inbox is wider.
       Message titles like "Helpdesksak #8386: [CMDB] …" want room; set
       min + width so the panel doesn't squeeze on narrow viewports. */
    width: 440px;
    min-width: 420px;
    max-width: min(480px, calc(100vw - 1.5rem));
    max-height: 520px;
    overflow: hidden;
    padding: 0;                /* rows provide their own padding */
    display: flex;
    flex-direction: column;
}
.notifications-dropdown-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.65rem 0.85rem;
    border-bottom: 1px solid var(--border);
    font-size: 0.9rem;
}
.notifications-dropdown-head strong { color: var(--fg); }
/* Scoped selector beats the generic `.dropdown-menu button` styling
   (same specificity class+tag), so "Merk alle som lest" rendres as an
   inline, muted link — ikke en full-width primary-looking knapp. */
.notifications-dropdown-head .notifications-mark-all {
    display: inline;
    width: auto;
    background: transparent;
    border: 0;
    color: var(--muted);
    font-size: 0.78rem;
    font-weight: 400;
    cursor: pointer;
    padding: 0;
    text-align: right;
    text-decoration: none;
    border-radius: 0;
}
.notifications-dropdown-head .notifications-mark-all:hover {
    background: transparent;
    color: var(--accent);
    text-decoration: underline;
}

.notifications-body {
    overflow-y: auto;
    padding: 0.35rem 0;
}
.notifications-section { padding: 0.25rem 0; }
.notifications-section h4 {
    margin: 0 0 0.2rem;
    padding: 0.35rem 0.85rem;
    font-size: 0.72rem;
    font-weight: 600;
    color: var(--muted);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}
.notifications-list {
    list-style: none;
    margin: 0;
    /* Small inset so the rounded row corners don't clash with the
       dropdown's outer rounded edge, and so unread rows read as
       distinct cards rather than wall-to-wall blocks. */
    padding: 0.25rem 0.35rem;
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
}
.notification-row {
    border-left: 3px solid transparent;
    border-radius: var(--radius);
    /* Anchor child has its own background-on-hover; keep it within
       the rounded shape. */
    overflow: hidden;
}
.notification-row.is-unread {
    border-left-color: var(--accent);
    background: var(--icon-blue-soft);
}
/* Direct-child selectors so we don't double-pad rows that have both an
   `<a>` wrapper AND a nested `.notification-row-body`. With link, the
   `<a>` is the direct child and gets padding; the body div inside
   doesn't. Without link, the body div is the direct child and gets the
   padding instead. Either way: a single padding-layer per row. */
.notification-row > a,
.notification-row > .notification-row-body {
    display: block;
    padding: 0.55rem 0.85rem;
    color: var(--fg);
    text-decoration: none;
    cursor: pointer;
}
.notification-row > a:hover,
.notification-row:hover > .notification-row-body { background: var(--shade-1); }
.notification-row-title {
    font-weight: 500;
    font-size: 0.88rem;
    line-height: 1.3;
    /* Long tokens like "Helpdesksak #8386:" used to break mid-word
       inside the narrow dropdown. Allow normal breaks on whitespace
       and only break words when nothing else fits. */
    overflow-wrap: anywhere;
    word-break: normal;
}
.notification-row-msg {
    font-size: 0.8rem;
    color: var(--muted);
    margin-top: 0.15rem;
    line-height: 1.35;
    overflow-wrap: anywhere;
    word-break: normal;
}
.notification-row-time {
    display: block;
    font-size: 0.72rem;
    margin-top: 0.15rem;
}

/* Mobile: drop the 420px min-width and re-anchor the panel to the
   viewport instead of the bell trigger. With min-width > viewport, the
   panel was 420px wide anchored to the bell's right edge — pushing the
   left edge off-screen. `position: fixed` breaks out of `.dropdown`'s
   positioning context so left/right viewport-margins work.

   Selector uses both classes (`.dropdown-menu.notifications-dropdown`)
   to win specificity over the generic `.dropdown-menu { position:
   absolute; right: 0 }` rule that lives further down in the source
   (would otherwise win the same-specificity tie via source order). */
@media (max-width: 600px) {
    .dropdown-menu.notifications-dropdown {
        position: fixed;
        top: calc(var(--agent-topbar-height, 64px) + 4px);
        left: 0.5rem;
        right: 0.5rem;
        width: auto;
        min-width: 0;
        max-width: none;
        max-height: calc(100vh - var(--agent-topbar-height, 64px) - 1rem);
    }
}

/* Action-row above the notifications list on /me/notifications.
   Right-aligned link-button for "Merk alle som lest" — secondary
   action, hence muted treatment vs. the primary `.btn` in the
   page-head above. */
.me-notifications-actions {
    display: flex;
    justify-content: flex-end;
    margin: 0 0 1rem;
}

/* ------ Toast notifications ------
   Stacked in a fixed column at bottom-right. Each toast is a self-closing
   card with a colored left-border matching the severity. Use toast.*
   helpers in /assets/js/components/toast.js — don't style other places
   to look like toasts. */
.toast-container {
    position: fixed;
    bottom: 1.25rem;
    right: 1.25rem;
    display: flex;
    flex-direction: column-reverse;
    gap: 0.5rem;
    z-index: 500;
    pointer-events: none;
}
.toast {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    min-width: 280px;
    max-width: 420px;
    padding: 0.75rem 0.9rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-left-width: 4px;
    border-radius: var(--radius);
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.1);
    opacity: 0;
    transform: translateY(8px);
    transition: opacity 0.15s, transform 0.15s;
    pointer-events: auto;
}
.toast.open { opacity: 1; transform: translateY(0); }
.toast-icon { flex-shrink: 0; font-size: 1.1rem; }
.toast-message { flex: 1; font-size: 0.9rem; color: var(--fg); line-height: 1.35; }
.toast-close {
    flex-shrink: 0;
    width: 24px;
    height: 24px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: 0;
    border-radius: 50%;
    color: var(--muted);
    cursor: pointer;
}
.toast-close:hover { background: var(--shade-1); color: var(--fg); }
/* Optional inline action button — used for confirm-style toasts
   (e.g. "New version available [Reload]"). Sits between message
   and the close-X. */
.toast-action {
    flex-shrink: 0;
    background: transparent;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
    color: var(--accent);
    font: inherit;
    font-size: 0.85rem;
    font-weight: 600;
    padding: 0.25rem 0.65rem;
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s;
}
.toast-action:hover { background: var(--shade-1); border-color: var(--accent); }
.toast-success { border-left-color: var(--icon-green); }
.toast-success .toast-icon { color: var(--icon-green); }
.toast-error { border-left-color: var(--icon-red); }
.toast-error .toast-icon { color: var(--icon-red); }
.toast-warning { border-left-color: var(--icon-amber); }
.toast-warning .toast-icon { color: var(--icon-amber); }
.toast-info { border-left-color: var(--accent); }
.toast-info .toast-icon { color: var(--accent); }

/* ------ Chip-input (multi-select with pills) ------
   Generic chip-list for tag-style multi-select fields (ticket categories,
   future: shared users, etc.). Selected values are removable pills;
   a "+ Legg til" trigger opens a .dropdown-menu with remaining options.
   Markup:
     <div class="chip-input dropdown" data-field="...">
         <div class="chip-input-list">
             <span class="chip" data-chip-id="1">Navn <button class="chip-remove">×</button></span>
             <button class="chip-add dropdown-trigger"><i class="fal fa-plus"></i> Legg til</button>
         </div>
         <div class="dropdown-menu chip-input-menu" hidden>
             <button data-add-id="2">Ny kategori</button>
         </div>
     </div>
*/
.chip-input-list {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.35rem;
    min-height: 34px;
}
.chip {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.2rem 0.2rem 0.2rem 0.55rem;
    background: var(--icon-blue-soft);
    color: var(--accent);
    border-radius: 999px;
    font-size: 0.82rem;
    font-weight: 500;
}
.chip-remove {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    border: 0;
    background: transparent;
    color: var(--accent);
    cursor: pointer;
    font-size: 0.75rem;
}
.chip-remove:hover { background: var(--accent); color: #fff; }
.chip-add {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.2rem 0.55rem;
    background: transparent;
    border: 1px dashed var(--border);
    border-radius: 999px;
    color: var(--muted);
    font-size: 0.82rem;
    cursor: pointer;
}
.chip-add:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
.chip-add:disabled { opacity: 0.5; cursor: not-allowed; }
.chip-input-menu {
    max-height: 240px;
    overflow-y: auto;
}
.chip-input-menu-empty {
    padding: 0.5rem 0.75rem;
    margin: 0;
    font-size: 0.85rem;
}

/* ------ Dropdown menu (generic) ------
   Click-to-open menu anchored to a trigger. Use anywhere a user clicks
   an ellipsis/avatar/chevron and gets a list of actions.
   Markup:
     <div class="dropdown">
         <button class="dropdown-trigger ...">…</button>
         <div class="dropdown-menu" hidden>
             <button><i class="fal fa-pen"></i> Rediger</button>
             <hr>
             <button class="is-danger"><i class="fal fa-trash"></i> Slett</button>
         </div>
     </div>
   The panel aligns top-right of its relative parent. Use `is-danger` on
   the item itself (not a separate class variant) for red destructive
   actions. */
.dropdown { position: relative; }
.dropdown-menu {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    min-width: 200px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
    padding: 0.35rem;
    z-index: 100;
}
.dropdown-menu a,
.dropdown-menu button {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    width: 100%;
    padding: 0.5rem 0.75rem;
    color: var(--fg);
    background: transparent;
    border: 0;
    border-radius: var(--radius);
    font-size: 0.9rem;
    font-weight: 500;
    cursor: pointer;
    text-align: left;
    text-decoration: none;
}
.dropdown-menu a:hover:not(:disabled),
.dropdown-menu button:hover:not(:disabled) { background: var(--shade-1); color: var(--accent); }
.dropdown-menu a:disabled,
.dropdown-menu button:disabled { color: var(--muted); cursor: not-allowed; }
.dropdown-menu p {
    padding: 0.5rem 0.75rem;
    margin: 0;
}
.dropdown-menu hr {
    border: 0;
    border-top: 1px solid var(--border);
    margin: 0.35rem 0;
}
.dropdown-menu i {
    width: 1.1em;
    text-align: center;
    color: var(--muted);
}
.dropdown-menu a:hover:not(:disabled) i,
.dropdown-menu button:hover:not(:disabled) i { color: var(--accent); }
/* Destructive action (delete, revoke) — red with soft red hover. */
.dropdown-menu .is-danger,
.dropdown-menu .is-danger i { color: var(--icon-red); }
.dropdown-menu .is-danger:hover:not(:disabled) { background: var(--icon-red-soft); color: var(--icon-red); }
.dropdown-menu .is-danger:hover:not(:disabled) i { color: var(--icon-red); }

/* Toggle-row inside a dropdown-menu — label on the left, switch on
   the right. Used e.g. for the "Dark mode"-toggle in the user-portal
   dropdown so the theme can be flipped without leaving the menu.
   Matches row padding/radius with the a/button rows above so it
   doesn't read as a foreign element. */
.dropdown-menu .dropdown-toggle-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.6rem;
    padding: 0.5rem 0.75rem;
    border-radius: var(--radius);
    cursor: pointer;
    font-size: 0.9rem;
    font-weight: 500;
    color: var(--fg);
}
.dropdown-menu .dropdown-toggle-row:hover { background: var(--shade-1); }
.dropdown-menu .dropdown-toggle-row > span:first-child {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
}

/* ------ Split-button ------
   Two-part button: main action (default) + chevron-trigger that opens
   `.dropdown-menu` with alternative actions. Visually a single pill —
   the seam between the two halves is a 1-pixel divider, not a gap.

   Markup:
     <div class="split-button">
       <button class="btn btn-primary split-button-main">Default</button>
       <div class="dropdown split-button-trigger-wrap">
         <button class="btn btn-primary split-button-trigger">▾</button>
         <div class="dropdown-menu split-button-menu" hidden>...</div>
       </div>
     </div>

   The two halves use the same .btn-{variant}, so colour swap is one-line.
   Per-variant overrides aren't needed — the divider uses rgba so it
   reads the same on any solid backdrop. */
.split-button { display: inline-flex; }
.split-button-trigger-wrap { display: inline-flex; }
/* Specificity boost (0,2,0) — `.btn` defines `border-radius: var(--radius)`
   later in the file with the same specificity, so without a parent prefix
   the `.btn` cascade wins and both halves end up fully rounded (looks
   like two separate buttons). */
.split-button > .split-button-main {
    border-top-right-radius: 0;
    border-bottom-right-radius: 0;
    border-right: 0;
}
.split-button .split-button-trigger {
    border-top-left-radius: 0;
    border-bottom-left-radius: 0;
    padding: 0 0.45rem;
    min-width: 0;
    /* Subtle inner-shadow seam so both halves read as a single button
       while still hinting where the chevron click zone starts. Darker
       than rgba-white — works on every solid backdrop. */
    box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15);
}
.split-button .split-button-trigger i { font-size: 0.75rem; }
.split-button-menu { min-width: 220px; }

@media (max-width: 600px) {
    .user-name { display: none; }
}

/* ------ Bottom-nav (mobile only) ------
   User-portal mobile shell. Hidden on desktop (≥ 600px), where the
   topbar handles all primary navigation. On mobile the topbar is
   hidden entirely (see media-query further down) and this nav is
   the only persistent chrome.

   4 equal slots: Home · My tickets · Cart · Profile. Active state =
   colored icon + label (iOS-style). Badges use the same visual style
   as `.nav-badge` in the topbar.

   Layout: `position: fixed; bottom: 0` — body padding-bottom is set
   in the @media block to make room. `safe-area-inset-bottom` pads
   the iPhone home-indicator area. */
.bottom-nav {
    display: none; /* shown by @media (max-width: 600px) below */
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    background: var(--surface);
    border-top: 1px solid var(--border);
    box-shadow: 0 -1px 4px rgba(0, 0, 0, 0.04);
    padding-bottom: env(safe-area-inset-bottom, 0);
    z-index: 50;
}
.bottom-nav-item {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.2rem;
    padding: 0.5rem 0.25rem;
    min-height: 56px;
    color: var(--muted);
    text-decoration: none;
    position: relative;
    transition: color 0.12s;
}
.bottom-nav-item:hover { color: var(--accent); }
.bottom-nav-icon { font-size: 1.3rem; line-height: 1; }
.bottom-nav-label { font-size: 0.7rem; font-weight: 500; line-height: 1; }
.bottom-nav-item.is-active { color: var(--accent); }
.bottom-nav-item.is-active .bottom-nav-label { font-weight: 600; }

.bottom-nav-badge {
    position: absolute;
    top: 4px;
    /* Place badge top-right of the icon (icon is centered horizontally,
       so we offset from center). 22px = half-width of the icon column +
       a few px gap. */
    left: calc(50% + 6px);
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    font-size: 0.7rem;
    font-weight: 700;
    color: #fff;
    /* Red — same rationale as `.nav-badge` above. */
    background: var(--icon-red);
    border-radius: 999px;
    display: flex;
    align-items: center;
    justify-content: center;
    line-height: 1;
}

/* ------ Main container ------ */
main#app {
    max-width: 1100px;
    margin: 2rem auto;
    padding: 0 1.25rem;
}

/* ------ Mobile shell (< 600px) ------
   Hide topbar entirely, show bottom-nav, pad body so content clears
   both the iOS notch (safe-area-inset-top) and the fixed bottom-nav
   (`56px` matches `.bottom-nav-item min-height`; `safe-area-inset-bottom`
   already lives inside `.bottom-nav`'s own padding so we only pad for
   the visible nav-band height itself).

   `main#app` padding reduced from 1.25rem (20px) to 0.75rem (12px) on
   mobile — keeps a bit of breathing room from the edge while letting
   tile rows fill more width. Placed AFTER the `main#app` block so the
   override wins via source-order (same specificity). */
@media (max-width: 600px) {
    /* Hard-stop horizontal overflow on BOTH html and body. Setting it on
     * body alone leaves html free to show a horizontal scrollbar when a
     * descendant overflows — and on mobile that scrollbar steals ~16px
     * from the visual viewport, hiding the bottom row of `position: fixed;
     * bottom: 0` content (i.e. the bottom-nav labels). Setting both
     * stops the scrollbar from ever appearing. */
    html, body { overflow-x: hidden; }
    body {
        padding-top: env(safe-area-inset-top, 0);
        /* 56px = .bottom-nav-item min-height. Adding the iOS home-indicator
         * safe-area too: the bottom-nav itself reserves that strip via its
         * own padding-bottom, so without this the last row of content sits
         * under the home-indicator area on notched devices. */
        padding-bottom: calc(56px + env(safe-area-inset-bottom, 0));
    }
    #app-header { display: none; }
    .bottom-nav { display: flex; }
    main#app { margin: 1rem auto; padding: 0 0.75rem; }
}

h1 { font-size: 1.65rem; margin: 0 0 1.25rem; }
h2 { font-size: 1.15rem; margin: 1.75rem 0 0.75rem; color: var(--fg); }

.muted { color: var(--muted); }
.error { color: var(--danger); font-weight: 600; }
/* Semantic text/icon color utilities — apply to inline icons in status
   feedback ("connection ok", "delivered", "send failed") instead of
   inline `style="color: var(--…)"`. Same tokens as buttons + alerts. */
.text-success { color: var(--success); }
.text-danger  { color: var(--danger); }
/* Tight variant for muted help-text directly under a heading — avoids
   the browser-default top margin on `<p>` collapsing the visual link
   to the heading above. Pair with `.muted` (`<p class="muted muted-tight">…</p>`). */
.muted-tight { margin-top: 0; }
/* Compact body text — slightly smaller than default for dense help-text
   inside form sections. Use sparingly: most text should stay at base size. */
.text-sm { font-size: 0.9rem; }
code {
    background: var(--shade-2);
    padding: 0.1em 0.4em;
    border-radius: 3px;
    font-size: 0.9em;
    /* Long unbroken tokens (e.g. config-keys, env vars, error codes
     * like `no_outbound_smtp_for_dept_X_or_global_fallback`) overflow
     * the container on mobile when they can't fit on one line. Allow
     * mid-token line breaks rather than horizontal overflow. */
    overflow-wrap: anywhere;
}

/* ------ Dashboard tiles ------ */
.tiles {
    display: grid;
    gap: 1rem;
    margin-bottom: 1.25rem;
}
.tiles-lg { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
.tiles-md { grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); }
/* Three equal columns, capped at 1/3 of the container — a single tile
   doesn't stretch edge-to-edge (which looked wrong with one item), and
   4+ tiles wrap onto a new row. Used for short lists like one
   department in the store. On mobile (< 600px) tiles go full-width:
   the small fixed tile felt orphaned next to mostly-empty space, and
   full-width matches the bottom-nav tab affordance. */
.tiles-fixed { grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 600px) {
    .tiles-fixed { grid-template-columns: 1fr; }
}

.tile {
    /* Surface-tokens + hover-lift arves fra :is()-blokken
       under "CANONICAL ROW-SURFACE". Her kun struktur. */
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    padding: 1.5rem;
    color: var(--fg);
    text-decoration: none;
}

/* Centered variant — icon sits above the title, no background bubble. */
.tile-centered {
    align-items: center;
    text-align: center;
    gap: 0.25rem;
    padding: 1.75rem 1.5rem;
}
.tiles-lg .tile-centered { padding: 2.5rem 1.5rem; }

.tile-icon-lg {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--icon-fg, var(--icon-blue));
    margin-bottom: 0.75rem;
    font-size: 2.5rem;
    line-height: 1;
}
.tiles-md .tile-icon-lg { font-size: 2rem; margin-bottom: 0.5rem; }

/* Old non-centered variant kept for any future use. */
.tile .tile-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border-radius: 10px;
    background: var(--icon-bg, var(--icon-blue-soft));
    color: var(--icon-fg, var(--icon-blue));
    margin-bottom: 0.5rem;
    font-size: 1.3rem;
}

.icon-blue   { --icon-bg: var(--icon-blue-soft);   --icon-fg: var(--icon-blue); }
.icon-green  { --icon-bg: var(--icon-green-soft);  --icon-fg: var(--icon-green); }
.icon-amber  { --icon-bg: var(--icon-amber-soft);  --icon-fg: var(--icon-amber); }
.icon-purple { --icon-bg: var(--icon-purple-soft); --icon-fg: var(--icon-purple); }
.icon-red    { --icon-bg: var(--icon-red-soft);    --icon-fg: var(--icon-red); }
.tile .tile-title { font-size: 1.05rem; font-weight: 600; color: var(--fg); }
.tile-centered .tile-title { font-size: 1.25rem; }
.tiles-md .tile-centered .tile-title { font-size: 1.05rem; }
.tile .tile-subtitle { color: var(--muted); font-size: 0.9rem; }

/* ------ Placeholder page (un-implemented features) ------ */
.placeholder {
    text-align: center;
    padding: 3rem 1rem;
}
.placeholder-icon {
    font-size: 3.5rem;
    color: var(--muted);
    margin-bottom: 1rem;
}
.placeholder h1 { margin-top: 0; }
.placeholder-actions { margin-top: 1.5rem; }
/* Offline shell — there's no topbar, so push content down a bit so it
   doesn't sit flush against the viewport top. Used by offline.html. */
.page-offline main { padding-top: 4rem; }

/* ------ Section head with "see all" link ------ */
.section-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    margin: 1.75rem 0 0.75rem;
}
.section-head h2 { margin: 0; }
.section-link { font-size: 0.9rem; }

.dashboard-recent { margin-top: 1rem; }
.dashboard-recent h2 { margin-top: 0; }

/* ------ Cards / panels ------ */
.card {
    /* Surface-tokens (background/border/radius/shadow) kommer fra den
       felles :is()-blokken — se "CANONICAL ROW-SURFACE" lenger nede. */
    padding: 1.25rem 1.5rem;
    margin-bottom: 1.25rem;
}
.card > h2:first-child { margin-top: 0; }

/* ------ Reusable list pattern (tickets, users, CMDB items, etc.) ------ */
/* See docs/components/list-item.md. */
.list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.list-item {
    /* Surface-tokens + hover-lift arves fra den felles :is()-blokken
       — se "CANONICAL ROW-SURFACE" lenger nede. Her kun struktur. */
    display: grid;
    grid-template-columns: auto 1fr auto;
    grid-template-areas:
        "icon primary   pill"
        "icon secondary tail";
    column-gap: 0.75rem;
    row-gap: 0.2rem;
    align-items: center;
    padding: 0.85rem 1rem;
    color: var(--fg);
    text-decoration: none;
    min-height: 44px;
}

.list-item-icon {
    grid-area: icon;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    border-radius: 50%;
    background: var(--icon-bg, var(--icon-blue-soft));
    color: var(--icon-fg, var(--icon-blue));
    font-size: 1rem;
    overflow: hidden;  /* clipper img-thumbs til sirkel */
    flex-shrink: 0;
}
/* Bilde-thumb (merc-items) fyller hele sirkelen */
.list-item-icon img { width: 100%; height: 100%; object-fit: cover; }
/* Avatar nestet inni — drop wrapper-bg for å unngå dobbelt-soft-bg */
.list-item-icon > .avatar { background: transparent; color: inherit; width: 100%; height: 100%; }
.list-item-primary {
    grid-area: primary;
    font-size: 1rem;
    font-weight: 500;
    line-height: 1.35;
    min-width: 0;
}
.list-item-id {
    color: var(--muted);
    font-family: ui-monospace, "SF Mono", Consolas, monospace;
    font-size: 0.82em;
    font-weight: 600;
    margin-right: 0.4rem;
}
.list-item-secondary {
    grid-area: secondary;
    color: var(--muted);
    font-size: 0.85rem;
    min-width: 0;
}
.list-item-tail {
    grid-area: tail;
    color: var(--muted);
    font-size: 0.85rem;
    text-align: right;
    white-space: nowrap;
}

/* `.is-unread` modifier — visual indicator on rows where the user has
   unread in-app notifications about the underlying entity (e.g. a sak
   with new comments). Top-right count-badge + bold title. Frontend
   sets `data-unread-count` on the row so CSS can show the number.
   Toggles based on `/api/me/notifications/unread-by-ticket`.

   Geometry: 20×20 perfect circle for 1–2 digits (no horizontal padding,
   `box-sizing: border-box` so the fixed dimensions include the border-
   radius). For "99+" the badge stretches into a pill — acceptable for
   the rare case. */
.list-item.is-unread { position: relative; }
.list-item.is-unread::after {
    content: attr(data-unread-count);
    position: absolute;
    top: 8px;
    right: 8px;
    min-width: 20px;
    height: 20px;
    padding: 0;
    box-sizing: border-box;
    font-size: 0.7rem;
    font-weight: 700;
    color: #fff;
    background: var(--icon-red);
    border-radius: 999px;
    display: flex;
    align-items: center;
    justify-content: center;
    line-height: 1;
}
.list-item.is-unread .list-item-primary { font-weight: 600; }

.list-item .status-pill {
    grid-area: pill;
    justify-self: end;
    align-self: start;
}

/* Column slot with label + value, used instead of plain secondary/tail. */
.list-item-col {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    min-width: 0;
}
.list-item-col .col-label {
    color: var(--muted);
    font-size: 0.75rem;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}
.list-item-col .col-value {
    font-size: 0.9rem;
    font-weight: 600;
    color: var(--fg);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.list-item-col .col-value i { margin-right: 0.25rem; }

/* Desktop: lay out like a table row — FIXED column widths so all rows
   align vertically even if content varies in length.

   Opt-in via `:has(.list-item-col)` — only lists that actually use
   the col system get the table grid. Lists with just primary+secondary
   (typically mobile-first user-portal views like /helpdesk) keep the
   default `auto 1fr auto` grid on desktop too, so a short secondary
   line doesn't sit next to 480px of empty column. */
@media (min-width: 720px) {
    .list-item:has(.list-item-col) {
        grid-template-columns: 44px 1fr 160px 160px 160px;
        grid-template-areas: "icon primary col1 col2 col3";
        column-gap: 1.25rem;
        row-gap: 0;
        padding: 0.85rem 1.25rem;
    }
    .list-item-col:nth-of-type(1) { grid-area: col1; }
    .list-item-col:nth-of-type(2) { grid-area: col2; }
    .list-item-col:nth-of-type(3) { grid-area: col3; }
    .list-item-secondary,
    .list-item-tail {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
    .list-item-tail { text-align: left; }
    .list-item .status-pill { align-self: center; }
}

/* ------ Compact variant: behold mobile-grid på desktop ------
   For lister i smale containere (drawer-paneler, sidebar-kolonner,
   andre 360–420px-omgivelser) hvor desktop-griddet med 480px+ av
   col1+col2+col3 ikke får plass. Behold .list/.list-item-markupen,
   bare overstyr grid-template'en. */
.list-compact .list-item {
    grid-template-columns: auto 1fr auto;
    grid-template-areas:
        "icon primary   pill"
        "icon secondary tail";
    column-gap: 0.6rem;
    row-gap: 0.15rem;
    padding: 0.6rem 0.8rem;
}
.list-compact .list-item-primary { font-size: 0.9rem; line-height: 1.3; }
.list-compact .list-item-secondary { font-size: 0.8rem; }

/* ------ Admin-variant: list-item med inline-actions ------
   Brukt i settings + scheduler + andre CRUD-views der hver rad har
   rediger/slett-knapper. Erstatter den utdaterte .admin-item-klassen
   (slettet 2026-04-25). Severity formidles via icon-color-class
   (.icon-{green,amber,red,blue,muted}) på .list-item-icon, ikke via
   border-strip. */
.list-item-with-actions {
    grid-template-columns: auto 1fr auto auto;
    grid-template-areas:
        "icon primary   meta actions"
        "icon secondary meta actions";
    align-items: center;
    row-gap: 0.4rem;
}
/* Variant without the actions column — CRUD rows where the whole row
   is clickable (no inline buttons). Same fluid grid as -with-actions
   but without reserving the trailing actions cell. Use with
   `.list-item.is-clickable` for the row-as-button affordance. */
.list-item-with-meta {
    grid-template-columns: auto 1fr auto;
    grid-template-areas:
        "icon primary   meta"
        "icon secondary meta";
    align-items: center;
    row-gap: 0.4rem;
}
/* CRUD rows never wrap the primary title — ellipsis when the cell is
   too narrow (typical in drawer context where width is constrained).
   Differs from clickable list-items (/agent/helpdesk tickets) which
   intentionally wrap long ticket titles. */
.list-item-with-actions .list-item-primary,
.list-item-with-meta .list-item-primary {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.list-item-meta {
    grid-area: meta;
    text-align: right;
    font-size: 0.82rem;
    color: var(--muted);
    min-width: 0;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    align-items: flex-end;
}
.list-item-meta > div, .list-item-meta > span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 100%;
}
.list-item-actions {
    grid-area: actions;
    display: flex;
    gap: 0.1rem;
    align-items: center;
    white-space: nowrap;
}
.list-item.is-deleted { opacity: 0.55; }
.list-item.is-deleted:hover { opacity: 0.75; }

/* Pointer cursor for clickable rows. <a class="list-item"> får det
   automatisk; <li class="list-item is-clickable" data-href="…"> og
   <li class="list-item user-link" data-user-id="…"> trenger eksplisitt
   pointer siden <li> ikke er en native interaktiv element. */
.list-item.is-clickable,
.list-item.user-link,
.surface.is-clickable,
.surface[role="button"] { cursor: pointer; }

/* Icon-cell color variants — solid bg + matching fg.
   Brukes på .list-item-icon for å formidle severity / kategori. */
.list-item-icon.icon-blue   { background: var(--icon-blue-soft);   color: var(--icon-blue); }
.list-item-icon.icon-green  { background: var(--icon-green-soft);  color: var(--icon-green); }
.list-item-icon.icon-amber  { background: var(--icon-amber-soft);  color: var(--icon-amber); }
.list-item-icon.icon-red    { background: var(--icon-red-soft);    color: var(--icon-red); }
.list-item-icon.icon-purple { background: var(--icon-purple-soft); color: var(--icon-purple); }
.list-item-icon.icon-muted  { background: var(--shade-2);          color: var(--muted); }

@media (min-width: 720px) {
    /* Desktop: meta-cellen får bredde-tak så aksjoner alltid lander til høyre */
    .list-item-with-actions {
        grid-template-columns: 44px 1fr minmax(0, 280px) auto;
    }
    .list-item-with-meta {
        grid-template-columns: 44px 1fr minmax(0, 280px);
    }
}

/* Mobile (<720px): stack the meta column below the primary text instead
 * of letting it compete for horizontal space. On a 375px viewport a long
 * "Sist endret: 2026-04-27 21:26:12"-style meta otherwise eats so much
 * width that the title truncates to a few characters ("Bravi…"). Meta
 * left-aligns under the title so the title can take the full row.
 *
 * Same treatment for .list-item-with-actions — its meta column was
 * pushing badge-rows + addresses + coordinates into a narrow strip,
 * causing overlap (location: coordinates over the address). Actions
 * stay anchored top-right next to the title; secondary + meta drop to
 * their own rows below so badges and the rest can breathe. */
@media (max-width: 719px) {
    .list-item-with-meta {
        grid-template-columns: auto 1fr;
        grid-template-areas:
            "icon primary"
            "icon secondary"
            "icon meta";
    }
    .list-item-with-meta .list-item-meta {
        text-align: left;
        align-items: flex-start;
    }
    .list-item-with-actions {
        grid-template-columns: auto 1fr auto;
        grid-template-areas:
            "icon primary   actions"
            "icon secondary secondary"
            "icon meta      meta";
    }
    .list-item-with-actions .list-item-meta {
        text-align: left;
        align-items: flex-start;
    }
}

/* ------ Badge — én pill-komponent, mange varianter ------
   Erstatter parallelle pill-systemer (.link-flag, .link-scope,
   .badge-deleted, .log-severity-pill, .admin-flag). Soft-tinted
   bakgrunn + matching tekst, valgfritt ikon-prefix.

   Bruk:
     <span class="badge badge-green">Aktiv</span>
     <span class="badge badge-amber"><i class="fal fa-clock"></i> Venter</span>

   For status-pill med fritt-valgt farge (fra DB) — se .status-pill
   som har egen --pill CSS-var. .badge er for predefinerte tokens. */
.badge {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.12rem 0.5rem;
    border-radius: 999px;
    font-size: 0.75rem;
    font-weight: 500;
    line-height: 1.4;
    white-space: nowrap;
    background: var(--shade-2);
    color: var(--muted);
}
.badge i { font-size: 0.7rem; }
.badge-blue   { background: var(--icon-blue-soft);   color: var(--icon-blue); }
.badge-green  { background: var(--icon-green-soft);  color: var(--icon-green); }
.badge-amber  { background: var(--icon-amber-soft);  color: var(--icon-amber); }
.badge-red    { background: var(--icon-red-soft);    color: var(--icon-red); }
.badge-purple { background: var(--icon-purple-soft); color: var(--icon-purple); }
.badge-muted  { background: var(--shade-2);          color: var(--muted); }

/* Domain-marker variant: customer / org name. Hidden on narrow phones
 * (where it's the least valuable badge — email + phone + status pull
 * more weight on a 375px viewport). Kept visible on desktop where the
 * extra context helps scanning a long user list. */
@media (max-width: 600px) {
    .badge-customer { display: none; }
}

/* Badge-row inside .list-item-secondary — gap mellom badges. Block-level
 * flex (not inline) so the row takes the full grid-cell width. That
 * gives `.contact-bit { max-width: 100% }` something concrete to size
 * against; inline-flex would shrink-to-fit content and a long email
 * would just push the whole row past the grid-cell edge. */
.list-item-secondary .badge-row {
    display: flex;
    flex-wrap: wrap;
    gap: 0.3rem;
    align-items: center;
    min-width: 0;
}
/* Contact bits ("📧 email", "📱 phone") inside a badge-row — keep the
 * icon and the text bound as one inline-flex unit so a long email
 * doesn't strand the icon on its own line when the row wraps. Long
 * values truncate with ellipsis instead of breaking mid-token (mid-
 * email reads weirdly: "...verylong.surname@compa…" beats "...e@no" on
 * its own line). Full value still reachable via the user-profile-drawer
 * that opens when the whole row is tapped. */
.list-item-secondary .badge-row > .contact-bit {
    display: inline-flex;
    align-items: baseline;
    gap: 0.35rem;
    min-width: 0;
    max-width: 100%;
}
.list-item-secondary .badge-row > .contact-bit > i { flex-shrink: 0; }
.list-item-secondary .badge-row > .contact-bit > span {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ------ Triage-seksjoner på /agent/helpdesk/pending ------
   To paneller: "Nye saker" (godkjenning, hd_tickets_new) og
   "Mangler tekniker" (åpne hd_tickets uten technician). Begge er
   1. linje sitt ansvar — derfor på samme skjerm. Visuell separator
   mellom dem så det er tydelig at det er to ulike køer med ulike
   action-knapper. */
.triage-section { margin-bottom: 2rem; }
.triage-section:last-child { margin-bottom: 0; }
.triage-section-head { margin-bottom: 0.6rem; }
.triage-section-title {
    margin: 0;
    font-size: 1.05rem;
    font-weight: 600;
    color: var(--fg);
    display: flex;
    align-items: center;
    gap: 0.5rem;
}
.triage-section-title i { color: var(--muted); }
.triage-section-count {
    font-size: 0.8rem;
    font-weight: 600;
    padding: 0.15rem 0.55rem;
    border-radius: 999px;
    background: var(--shade-2);
    color: var(--muted);
}
.triage-section-sub { margin: 0.2rem 0 0; font-size: 0.85rem; }
.triage-section-empty { padding: 0.6rem 0; }

/* Saker uten tekniker får venstre-stripe i amber så de visuelt skiller
   seg fra pending-rader uten å skrike. Høyprio-ramme legges utenpå. */
.pending-row-unassigned {
    border-left: 3px solid var(--icon-amber);
}
.pending-row-high {
    border-left-color: var(--icon-red);
}

/* ------ .pending-row (strukturelt — kun grid/layout) ------ */
/* Bruk: /agent/helpdesk/pending (match ticket_list_item_approve.jsr).
   Surface-design (background/border/shadow/radius) kommer fra den
   felles :is()-blokken lenger nede — IKKE dupliser tokens her. */
.pending-row {
    display: grid;
    grid-template-columns: auto 1fr;
    grid-template-areas:
        "avatar body"
        ".      actions";
    column-gap: 1rem;
    row-gap: 0.75rem;
    align-items: start;
    padding: 1rem 1.25rem;
    transition: opacity 0.25s ease, transform 0.25s ease;
}
/* Reject animation — opacity + small scale-down before the row is
   removed from the DOM, so the user sees that "yes, this disappeared".
   Set by JS in rejectPending. */
.pending-row.is-removing {
    opacity: 0;
    transform: scale(0.96);
    pointer-events: none;
}
/* Approved row — agent stays on the pending list to batch-approve more,
   so we keep the row visible but visually mark it as done: dimmed
   surface, green checkmark badge, and the action-cell swapped to a
   single "Åpne sak"-link. */
.pending-row.is-approved {
    background: var(--icon-green-soft);
    border-color: var(--icon-green);
}
.pending-row-approved-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.4rem 0.6rem;
    color: var(--icon-green);
    font-size: 0.9rem;
    font-weight: 600;
}
.pending-row-avatar { grid-area: avatar; }
.pending-row-body   { grid-area: body; min-width: 0; }
.pending-row-actions {
    grid-area: actions;
    justify-self: end;
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
}
.pending-row-title {
    font-size: 1rem;
    font-weight: 600;
    line-height: 1.35;
    color: var(--fg);
}
.pending-row-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem 1rem;
    margin-top: 0.3rem;
    font-size: 0.85rem;
}
.pending-row-meta .user-link { color: inherit; }
.pending-row-inquery {
    margin-top: 0.65rem;
    font-size: 0.9rem;
    line-height: 1.5;
    color: var(--fg);
    display: -webkit-box;
    -webkit-line-clamp: 4;
    -webkit-box-orient: vertical;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: normal;
}
@media (max-width: 720px) {
    .pending-row { grid-template-areas: "avatar body" "actions actions"; }
    .pending-row-actions { justify-self: stretch; }
    .pending-row-actions .btn { flex: 1; }
}

/* ------ .mention-row (strukturelt — kun grid/layout) ------ */
/* Bruk: /agent/helpdesk/mentions (match gammel mentions-feed).
   Surface-design kommer fra felles :is()-blokken. */
.mention-row {
    display: grid;
    grid-template-columns: auto 1fr auto;
    grid-template-areas: "icon body time";
    column-gap: 1rem;
    row-gap: 0.15rem;
    align-items: start;
    padding: 0.85rem 1.25rem;
    color: var(--fg);
    text-decoration: none;
}
.mention-row-icon {
    grid-area: icon;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    border-radius: 8px;
    background: var(--icon-bg, var(--icon-green-soft));
    color: var(--icon-fg, var(--icon-green));
    font-size: 1rem;
}
.mention-row-body { grid-area: body; min-width: 0; }
.mention-row-heading {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem 0.35rem;
    align-items: baseline;
    font-size: 0.95rem;
    line-height: 1.35;
}
.mention-row-ticket {
    font-weight: 500;
    color: var(--fg);
}
.mention-row-preview {
    margin-top: 0.3rem;
    color: var(--muted);
    font-size: 0.88rem;
    line-height: 1.4;
    overflow: hidden;
    text-overflow: ellipsis;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}
.mention-row-time {
    grid-area: time;
    color: var(--muted);
    font-size: 0.82rem;
    white-space: nowrap;
    padding-top: 0.2rem;
}
/* Unread state — small "Ulest" pill inline next to the heading,
 * plus a subtle left-border accent on the surface so the eye finds
 * unread rows when scanning the list. Both fade away once the row
 * becomes read (no class → no styling). */
.mention-row-unread {
    display: inline-block;
    padding: 0.1rem 0.45rem;
    margin-left: 0.4rem;
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    border-radius: 999px;
    background: var(--icon-blue-soft);
    color: var(--accent);
}
.mention-row.is-unread {
    border-left: 3px solid var(--accent);
}
/* Narrow phones: drop the time column, time stacks under body on its
 * own row. Keeps the icon-column anchored on the left so the row still
 * reads as a list-item, just without a fixed time-anchor on the right. */
@media (max-width: 480px) {
    .mention-row {
        grid-template-columns: auto 1fr;
        grid-template-areas:
            "icon body"
            "icon time";
    }
    .mention-row-time { padding-top: 0; }
}

/* ==============================================================
   CANONICAL ROW-SURFACE (binding — se docs/design.md §Surface tokens)
   --------------------------------------------------------------
   Alle kort-/rad-/item-flater bruker `.surface`-utility-klassen.
   Påføres eksplisitt i markup ved siden av domain-klassen som styrer
   layout/struktur:

       <li class="surface list-item">…</li>
       <a  class="surface tile">…</a>
       <button class="surface choice-card">…</button>

   Surface-tokenene (background/border/radius/shadow) defineres KUN her.
   Domene-klasser (`.list-item`, `.tile`, …) skal kun definere struktur
   (grid, padding, gap, layout-modifiers) — IKKE skriv tokenene på nytt.

   Hover-lift håndteres separat under (klikkbare varianter løftes; rader
   med kun inline-knapper løfter ikke).
   ============================================================== */
.surface {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
}
/* Hover-lift = "denne raden er klikkbar". Gjelder kun rader som faktisk
   er klikkbare i sin helhet:
     - <a class="list-item">         (lenke-rad, naturlig klikkbar)
     - .list-item.is-clickable       (med data-href / egen click-handler)
     - .list-item.user-link          (åpner profil-drawer)
     - .mention-row, .agent-ticket-row, .pending-row (alltid klikkbare)
   En .list-item.list-item-with-actions UTEN noen av flagg-klassene
   over har inline-knapper, og selve raden er IKKE klikkbar — derfor
   ingen hover-lift (false-affordance unngås).
   Se docs/design.md §Hover-affordance. */
a.surface,
.surface.is-clickable,
.surface[role="button"],
a.list-item,
.list-item.is-clickable,
.list-item.user-link,
.mention-row,
.agent-ticket-row,
.pending-row,
.tile,
.settings-tile,
.choice-card {
    transition: border-color 0.15s, box-shadow 0.15s, transform 0.15s;
}
a.surface:hover,           a.surface:focus-visible,
.surface.is-clickable:hover,  .surface.is-clickable:focus-visible,
.surface[role="button"]:hover, .surface[role="button"]:focus-visible,
a.list-item:hover,         a.list-item:focus-visible,
.list-item.is-clickable:hover,  .list-item.is-clickable:focus-visible,
.list-item.user-link:hover,     .list-item.user-link:focus-visible,
.mention-row:hover,        .mention-row:focus-visible,
.agent-ticket-row:hover,   .agent-ticket-row:focus-visible,
.pending-row:hover,        .pending-row:focus-visible,
.tile:hover,               .tile:focus-visible,
.settings-tile:hover,      .settings-tile:focus-visible,
.choice-card:hover,        .choice-card:focus-visible {
    border-color: var(--accent);
    box-shadow: var(--shadow);
    color: var(--fg);  /* motvirk default <a>:hover-farge */
    transform: translateY(-1px);
}

/* Status select in agent ticket sidebar */
.status-select {
    width: 100%;
    padding: 0.65em 0.8em;
    font-size: 1rem;
    font-weight: 600;
    color: #fff;
    background: var(--pill, #888);
    border: 0;
    border-radius: var(--radius);
    cursor: pointer;
    appearance: none;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2'><polyline points='6 9 12 15 18 9'/></svg>");
    background-repeat: no-repeat;
    background-position: right 0.75rem center;
    padding-right: 2rem;
}
.status-select option { color: var(--fg); background: #fff; }

/* ------ Page head (title + action button) ------ */
.page-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    margin-bottom: 1rem;
    flex-wrap: wrap;
}
.page-head h1 {
    margin: 0;
    font-size: 1.65rem;   /* per docs/design.md §Typography */
    font-weight: 600;
}

/* ------ Forms: checkboxes, split actions ------ */
label.checkbox {
    display: flex;
    flex-direction: row;
    align-items: flex-start;
    gap: 0.7rem;
    padding: 0.85rem 1rem;
    background: var(--shade-1);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s, color 0.15s;
}
label.checkbox input {
    margin: 0.15em 0 0 0;
    flex-shrink: 0;
    width: 18px;
    height: 18px;
    cursor: pointer;
    accent-color: var(--accent);
}
label.checkbox > span {
    font-weight: 500;
    color: var(--fg);
    text-transform: none;
    font-size: 0.95rem;
    flex: 1;
    line-height: 1.4;
}

/* Confirm: turns green when checked. */
label.checkbox-confirm:has(input:checked) {
    background: var(--icon-green-soft);
    border-color: rgba(16, 185, 129, 0.4);
}
label.checkbox-confirm:has(input:checked) > span {
    color: var(--icon-green);
}
label.checkbox-confirm input:checked { accent-color: var(--icon-green); }

/* Critical: turns red when checked, reveals warning panel. */
label.checkbox-critical:has(input:checked) {
    background: var(--icon-red-soft);
    border-color: rgba(239, 68, 68, 0.4);
}
label.checkbox-critical:has(input:checked) > span {
    color: var(--icon-red);
}
label.checkbox-critical input:checked { accent-color: var(--icon-red); }

.critical-warning {
    /* Visually attached to the .checkbox-critical above — shared border,
       only bottom corners rounded. Negative margin-top cancels the
       parent's flex `gap: 1rem` (.new-ticket-form) so the two blocks
       merge into one alert. If the parent gap changes, update here. */
    display: none;
    margin: -1rem 0 0;
    padding: 1rem 1.25rem;
    background: var(--icon-red-soft);
    border: 1px solid rgba(239, 68, 68, 0.4);
    border-top: 0;
    border-radius: 0 0 var(--radius) var(--radius);
    color: var(--icon-red);
    font-size: 0.92rem;
    line-height: 1.5;
}
.critical-warning p { margin: 0 0 0.6rem; }
.critical-warning p:last-child { margin-bottom: 0; font-weight: 700; }
label.checkbox-critical:has(input:checked) {
    border-bottom-left-radius: 0;
    border-bottom-right-radius: 0;
    border-bottom-color: transparent;
}
label.checkbox-critical:has(input:checked) + .critical-warning { display: block; }

.form-actions-split {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    margin-top: 0.75rem;
}
/* .button.secondary handled by the main button system below (btn-ghost). */

/* Canonical action-bar — submit/cancel always bottom-right in modals,
   drawers, and inline forms. See design.md §Forms §Action bar.
   Used by both agent and user-portal shells (modal in /fagansvarlige
   pulls this from main.css; agent settings pages reuse it).
   Modifier: .admin-form-actions-split splits actions onto two ends
   (e.g. "Slett" leading, Save/Cancel trailing) — defined in agent.css
   since only agent forms need that variant today. */
.admin-form-actions {
    display: flex;
    justify-content: flex-end;
    gap: 0.5rem;
    margin-top: 0.5rem;
    /* Wrap if 3+ buttons can't fit on one row (e.g., the integrations
     * detail form has Avbryt / Test tilkobling / Synk brukere / Lagre).
     * Without wrap the leading button gets clipped off the left edge. */
    flex-wrap: wrap;
}
/* Mobile: stack buttons vertically, each taking full width — much
 * easier to hit on a 375px viewport than 4 wrapping pills, and keeps
 * the "primary at the natural end" reading order (Lagre at bottom). */
@media (max-width: 600px) {
    .admin-form-actions { flex-direction: column; align-items: stretch; }
    .admin-form-actions > .btn { width: 100%; justify-content: center; }
}

.status-pill {
    display: inline-block;
    padding: 0.25em 0.75em;
    font-size: 0.8em;
    font-weight: 600;
    color: #fff;
    background: var(--pill, #888);
    border-radius: 999px;
    white-space: nowrap;
}

/* ------ Forms ------ */
form {
    display: grid;
    gap: 1rem;
    margin-top: 1.5rem;
}
form label { display: grid; gap: 0.3rem; }
form label > span { font-weight: 600; color: var(--muted); font-size: 0.9rem; }
input[type="email"],
input[type="password"],
input[type="text"],
input[type="search"],
input[type="tel"],
input[type="url"],
input[type="number"],
input[type="date"],
input[type="datetime-local"],
textarea,
select {
    padding: 0.6em 0.8em;
    font-size: 1rem;
    font-family: inherit;
    color: var(--fg);
    background: var(--surface);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
}
input:focus, textarea:focus, select:focus {
    outline: 2px solid rgba(54, 150, 252, 0.4);
    outline-offset: 0;
    border-color: var(--accent);
}
/* ------ Store / Merchandise (user-portal /store) ------ */
.store-featured-section { margin-top: 2rem; }
.store-featured-section h2 { font-size: 1.1rem; font-weight: 600; margin: 0 0 0.75rem; }
/* Section-titler i butikken (Anbefalte varer / Alle varer-skille på
   department-view). Samme typografiske vekt som .store-featured-
   section h2 så det ikke skifter rytme mellom de to seksjonene. */
.store-section-heading { font-size: 1.1rem; font-weight: 600; margin: 1.5rem 0 0.75rem; }
.store-featured-section + .store-section-heading { margin-top: 1.5rem; }
.store-featured-section .store-section-heading { margin-top: 0; }

/* Generic search input — magnifier icon + input in one pill with a
   focus ring. Mirrors `.combo-search-field` (the typeahead field) but
   without the JS dependency, so simple filter inputs (store search,
   keyword filters) can share the same look. */
.search-bar {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    width: 100%;
    max-width: 520px;
    padding: 0 0.85em;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    cursor: text;
    transition: border-color 0.12s, box-shadow 0.12s;
}
.search-bar:focus-within {
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--icon-blue-soft);
}
.search-bar i { color: var(--muted); font-size: 0.85rem; flex-shrink: 0; }
.search-bar input {
    flex: 1;
    min-width: 0;
    padding: 0.55em 0;
    border: 0;
    background: transparent;
    font-family: inherit;
    font-size: 0.95rem;
    color: var(--fg);
}
.search-bar input:focus { outline: none; }

/* Top bar on store-shell pages: title on the left, search on the right.
   Communicates that search is global to the store, not category-scoped.
   Wraps on narrow screens. */
.store-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    margin: 0.5rem 0 0.75rem;
}
.store-header h1 {
    margin: 0;
    font-size: 1.65rem;
    color: var(--fg);
}
.store-header .search-bar { flex: 0 1 360px; }
/* Store shell — two-column layout used on /store/department/:id and
   /store/product/:id. The sidebar holds category navigation for the
   selected department and is shared across both pages. */
.store-shell {
    display: grid;
    grid-template-columns: 220px minmax(0, 1fr);
    gap: 1.75rem;
    align-items: flex-start;
}
@media (max-width: 720px) {
    /* `minmax(0, 1fr)` (not bare `1fr`) — without the explicit `0`
       minimum, the grid item's default `min-width: auto` lets the
       chip-row's intrinsic content-width force the grid cell (and
       thus the page) to grow horizontally, making the entire page
       scroll instead of just the chip row. */
    .store-shell { grid-template-columns: minmax(0, 1fr); }
}
.store-sidebar {
    position: sticky;
    top: 1rem;
    align-self: start;
}
.store-sidebar-title {
    margin: 0 0 0.6rem;
    font-size: 0.78rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--muted);
}
.store-cat-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}
.store-cat {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    padding: 0.55rem 0.75rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    color: var(--fg);
    font-size: 0.9rem;
    text-decoration: none;
    transition: background 0.12s, border-color 0.12s, color 0.12s;
}
.store-cat:hover { background: var(--shade-1); color: var(--accent); border-color: var(--accent); }
.store-cat i { color: var(--muted); font-size: 0.8rem; }
.store-cat.is-active {
    background: var(--icon-blue-soft);
    border-color: var(--accent);
    color: var(--accent);
    font-weight: 600;
}
.store-cat.is-active i { color: var(--accent); }

/* Mobile overrides for the store sidebar/category list. Placed AFTER
   the defaults above so equal-specificity rules win via source order
   (same gotcha as `main#app` earlier). */
@media (max-width: 720px) {
    /* Drop sticky positioning on mobile — without a side-by-side
       sibling to stick beside, the sticky sidebar would float on top
       of the product grid as the user scrolls (the sticky containing
       block extends through the whole .store-shell box). */
    .store-sidebar {
        position: static;
        top: auto;
        margin-bottom: 1rem;
    }
    /* Convert the vertical category list to a horizontal scroll-chip
       row — a common e-commerce mobile pattern (Apple Store, Amazon,
       Komplett). Saves vertical space so products are immediately
       visible, while keeping all categories one swipe away. */
    .store-cat-list {
        flex-direction: row;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        gap: 0.4rem;
        /* Hide scrollbar — momentum-scroll is the mobile affordance */
        scrollbar-width: none;
    }
    .store-cat-list::-webkit-scrollbar { display: none; }
    .store-cat {
        flex: 0 0 auto;
        white-space: nowrap;
        padding: 0.5rem 0.9rem;
        border-radius: 999px;  /* Pill shape — chip convention */
    }
    /* No chevron in chip mode — the row is horizontal, the icon would
       compete with the next chip for visual space. */
    .store-cat i { display: none; }
}

/* Collapsible info block below the tile rows on /store-landing.
   Rendered as a <details> element so the billing/legal fine print
   doesn't dominate the landing page. The user clicks the summary
   row to expand. */
.store-info {
    margin-top: 2.5rem;
    max-width: 760px;
    margin-left: auto;
    margin-right: auto;
    padding: 0 0.5rem;
    color: var(--muted);
    font-size: 0.9rem;
    line-height: 1.55;
}
.store-info > summary {
    cursor: pointer;
    padding: 0.5rem 0;
    text-align: center;
    color: var(--muted);
    font-weight: 500;
    list-style: none;  /* Hide default disclosure triangle */
}
.store-info > summary::-webkit-details-marker { display: none; }
.store-info-chevron {
    margin-right: 0.5rem;
    font-size: 0.75rem;
    transition: transform 0.15s;
}
.store-info[open] .store-info-chevron { transform: rotate(180deg); }
.store-info p {
    margin: 0.75rem 0 0;
    text-align: center;
}
.store-info-strong { font-weight: 600; color: var(--fg); }
.store-info-note { font-style: italic; }

.product-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 1rem;
}
/* Surface + hover-lift arves via .surface + a.surface i markup. Her
   kun struktur. */
.product-card {
    overflow: hidden;
    text-decoration: none;
    color: inherit;
    display: flex;
    flex-direction: column;
}
.product-card-image {
    aspect-ratio: 1;
    background: var(--shade-1);
    display: flex;
    align-items: center;
    justify-content: center;
}
.product-card-image img { width: 100%; height: 100%; object-fit: cover; }
.product-card-empty { color: var(--muted); font-size: 2rem; }
.product-card-body {
    padding: 0.75rem 1rem 1rem;
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}
.product-card-title { font-weight: 600; }
.product-card-subtitle { font-size: 0.85rem; }
.product-card-price { font-weight: 600; font-variant-numeric: tabular-nums; margin-top: 0.4rem; }

/* Admin variant of .product-card used on /agent/merc/items. Same card
 * shell + grid as the user-facing store, plus three image overlays:
 *   - top-right pen button → edit page (stopPropagation so the card
 *     click below doesn't double-fire and open the drawer)
 *   - bottom-left status pill (Skjult / Slettet)
 *   - top-left amber star when item.featured
 * Card click itself opens the read-only product-detail-drawer. */
.agent-merc-card { cursor: pointer; }
.agent-merc-card.is-deleted { opacity: 0.6; }
.agent-merc-card .product-card-image { position: relative; }
.agent-merc-card-edit {
    position: absolute;
    top: 0.5rem;
    right: 0.5rem;
    width: 36px;
    height: 36px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 50%;
    color: var(--accent);
    cursor: pointer;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15);
    transition: border-color 0.12s, color 0.12s;
    z-index: 2;
}
.agent-merc-card-edit:hover { border-color: var(--accent); }
.agent-merc-card-status {
    position: absolute;
    bottom: 0.5rem;
    left: 0.5rem;
    padding: 0.2rem 0.55rem;
    border-radius: 999px;
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    color: #fff;
    z-index: 2;
}
.agent-merc-card-status-deleted { background: var(--danger); }
.agent-merc-card-status-hidden  { background: var(--muted); }
.agent-merc-card-featured {
    position: absolute;
    top: 0.5rem;
    left: 0.5rem;
    width: 28px;
    height: 28px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--surface);
    border-radius: 50%;
    color: var(--icon-amber);
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15);
    z-index: 2;
}

/* Product detail (/store/product/:id) */
.product-detail {
    display: grid;
    grid-template-columns: minmax(240px, 1fr) 1.25fr;
    gap: 2rem;
    align-items: flex-start;
}
@media (max-width: 720px) {
    .product-detail { grid-template-columns: 1fr; }
}
.product-detail-gallery { display: grid; gap: 0.5rem; }
/* The element is a <button> so the main image can open the lightbox on
   click — reset button defaults (font, padding, text-align). cursor:
   zoom-in communicates that clicking gives a full-size view. */
.product-detail-main {
    aspect-ratio: 1;
    background: var(--shade-1);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    font: inherit;
    color: inherit;
    cursor: zoom-in;
    transition: border-color 0.12s, box-shadow 0.12s;
}
.product-detail-main:hover { border-color: var(--accent); box-shadow: 0 4px 14px rgba(0,0,0,0.06); }
.product-detail-main:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.product-detail-main img { width: 100%; height: 100%; object-fit: contain; background: white; }
.product-detail-thumbs {
    display: flex;
    gap: 0.4rem;
    flex-wrap: wrap;
}
.product-detail-thumb {
    width: 60px;
    height: 60px;
    border: 2px solid var(--border);
    border-radius: var(--radius);
    overflow: hidden;
    background: var(--surface);
    padding: 0;
    cursor: pointer;
}
.product-detail-thumb.is-active { border-color: var(--accent); }
.product-detail-thumb img { width: 100%; height: 100%; object-fit: cover; }

.product-detail-meta h1 { margin: 0 0 0.3rem; }
.product-detail-summary { color: var(--muted); margin: 0 0 1rem; }
.product-detail-price {
    display: flex;
    align-items: baseline;
    gap: 0.35rem;
    margin-bottom: 1rem;
}
.product-detail-price-amount { font-size: 1.6rem; font-weight: 700; color: var(--accent); font-variant-numeric: tabular-nums; }
.add-to-cart-form {
    display: flex;
    gap: 0.75rem;
    align-items: end;
    margin-top: 0;
}
.add-to-cart-form label {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    flex: 0 0 auto;
}
/* Antall-feltet trenger plass til 1–4 siffer, ikke en hel ord-input.
   Eksplisitt smal bredde — browser-default `size=20` ville gitt ~14rem. */
.add-to-cart-form input[type="number"] {
    width: 4.5rem;
    padding: 0.6em 0.8em;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
    font-size: 1rem;
    box-sizing: border-box;
}
.product-detail-link { margin-top: 1rem; }

/* Vises i stedet for add-to-cart-form når produktet er soft-deleted
   eller fjernet fra butikken. Bruker info-bar-warning-stilen som
   grunn-utseende, men trenger litt eget mellomrom under pris. */
.product-detail-unavailable {
    margin-top: 0;
    margin-bottom: 1rem;
}

.product-detail-description {
    grid-column: 1 / -1;
    margin-top: 1.5rem;
}
.product-detail-description h2 { font-size: 1.1rem; font-weight: 600; margin: 0 0 0.5rem; }
.product-detail-description-body { line-height: 1.5; }

.product-detail-accessories { margin-top: 2.5rem; }
.product-detail-accessories h2 { font-size: 1.1rem; font-weight: 600; margin: 0 0 0.75rem; }

/* Cart (/store/cart) */
.cart-empty {
    text-align: center;
    padding: 3rem 1rem;
    color: var(--muted);
}
.cart-empty i { color: var(--border); margin-bottom: 1rem; display: block; }
.cart-empty p { margin-bottom: 1.5rem; }

.cart-dept { margin-bottom: 2rem; }
.cart-dept h2 { font-size: 1rem; font-weight: 600; color: var(--muted); margin: 0 0 0.5rem; }
.cart-lines { list-style: none; padding: 0; margin: 0; display: grid; gap: 0.5rem; }
.cart-line {
    display: grid;
    grid-template-columns: 60px 1fr 80px 100px 40px;
    gap: 0.75rem;
    align-items: center;
    padding: 0.6rem 0.75rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
}
.cart-line.is-unavailable { background: #fff6f6; }
.cart-line-thumb {
    width: 60px;
    height: 60px;
    border-radius: var(--radius);
    overflow: hidden;
    background: var(--shade-1);
    display: flex;
    align-items: center;
    justify-content: center;
}
.cart-line-thumb img { width: 100%; height: 100%; object-fit: cover; }
.cart-line-body { min-width: 0; }
.cart-line-title { font-weight: 600; }
.cart-line-title a { color: inherit; text-decoration: none; }
.cart-line-title a:hover { color: var(--accent); }
.cart-line-warning { color: var(--danger); font-size: 0.85rem; margin-top: 0.2rem; }
.cart-line-price { font-size: 0.85rem; margin-top: 0.15rem; }
.cart-line-qty input {
    width: 70px;
    padding: 0.35em 0.5em;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
    font-variant-numeric: tabular-nums;
}
.cart-line-sum { text-align: right; font-weight: 600; font-variant-numeric: tabular-nums; }
.cart-subtotal { text-align: right; margin: 0.6rem 0.75rem 0; font-size: 0.9rem; }

.cart-totals {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 1rem;
    border-top: 2px solid var(--border);
    margin: 1rem 0;
    font-size: 1.1rem;
}
/* Surface arves fra .surface-utility i markup. Her kun struktur. */
.cart-checkout-form {
    display: grid;
    gap: 1rem;
    padding: 1rem 1.25rem;
}
.cart-checkout-form label { display: flex; flex-direction: column; gap: 0.25rem; }
.cart-checkout-form input[type="text"] {
    padding: 0.6em 0.8em;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
}
/* Fakturakode er typisk 5–10 tegn — full-bredde input ser feil ut. */
.cart-checkout-invoice input[type="text"] { max-width: 200px; }
.cart-checkout-invoice .me-hint { font-size: 0.8rem; }
.cart-actions {
    display: flex;
    justify-content: space-between;
    gap: 0.75rem;
    flex-wrap: wrap;
}
.cart-note { font-size: 0.85rem; margin: 0; }

/* Mobile: stack the 5-col grid into a 3-col / 2-row layout. Thumb spans
 * both rows on the left; row 1 = title/price + trash, row 2 = qty + sum.
 * Keeps the markup unchanged — only grid-areas reflow. */
@media (max-width: 600px) {
    .cart-line {
        grid-template-columns: 60px 1fr auto;
        grid-template-areas:
            "thumb body remove"
            "thumb qty  sum";
        align-items: start;
        column-gap: 0.6rem;
        row-gap: 0.4rem;
    }
    .cart-line-thumb  { grid-area: thumb; }
    .cart-line-body   { grid-area: body; }
    .cart-line-qty    { grid-area: qty; align-self: center; }
    .cart-line-sum    { grid-area: sum; align-self: center; }
    .cart-line-remove { grid-area: remove; justify-self: end; }
    .cart-line-qty input { width: 64px; }
    .cart-checkout-invoice input[type="text"] { max-width: 100%; }
}

/* Invoicer (/store/invoicer) */
.invoicer-section { margin-top: 1.5rem; }
.invoicer-form {
    display: grid;
    gap: 0.75rem;
    max-width: 480px;
}
.invoicer-form input[type="text"] {
    padding: 0.6em 0.8em;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
    font-family: inherit;
    font-size: 1rem;
    letter-spacing: 0.02em;
}
.invoicer-hint { font-size: 0.85rem; }
.invoicer-code-set {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 1rem;
    font-size: 1.1rem;
}
.invoicer-code {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 1.25rem;
    color: var(--accent);
}
.invoicer-locked-note { font-size: 0.85rem; margin: 0.5rem 0 0; }

.invoicer-stats {
    display: flex;
    gap: 1rem;
    margin: 1rem 0;
}
.invoicer-stat {
    padding: 1rem 1.25rem;
    flex: 1;
    text-align: center;
}
.invoicer-stat-value { font-size: 1.6rem; font-weight: 700; color: var(--accent); }
.invoicer-stat-label { color: var(--muted); font-size: 0.85rem; margin-top: 0.2rem; }

.invoicer-orders { display: grid; gap: 1rem; }
.invoicer-order {
    padding: 0.75rem 1rem;
}
.invoicer-order-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    margin-bottom: 0.5rem;
}
.invoicer-order-sum { font-weight: 600; font-variant-numeric: tabular-nums; }
.invoicer-lines { list-style: none; padding: 0; margin: 0; display: grid; gap: 0.25rem; }
.invoicer-line {
    display: grid;
    grid-template-columns: 1fr auto auto;
    gap: 0.75rem;
    font-size: 0.9rem;
}
.invoicer-line-title { font-weight: 500; }
.invoicer-line-sum { font-weight: 600; font-variant-numeric: tabular-nums; }

/* ------ Info-bar (kategorisert info-rad) ------
   Tynn, kategori-kodet rad for type-merket informasjon (driftsmeldinger,
   varsler, deploy-status, lignende). Surface-tokens arves fra
   CANONICAL ROW-SURFACE :is()-blokken — her kun struktur + type-varianter
   som overstyrer bakgrunn. Container er den kanoniske `.list`. Klikkbar
   variant via role="button"; klikk åpner typisk en detalj-modal.
   Se docs/components/info-bar.md for full pattern-spec. */
.info-bar {
    padding: 0.75rem 1rem;
    border-left: 4px solid var(--accent);
}
.info-bar-head {
    display: flex;
    align-items: center;
    gap: 0.6rem;
}
.info-bar-head h2 {
    flex: 1;
    margin: 0;
    font-size: 1rem;
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.info-bar-icon { color: var(--muted); font-size: 1.1rem; }
.info-bar-date { color: var(--muted); font-size: 0.85rem; white-space: nowrap; }

/* Type-varianter — overstyrer surface-bakgrunn for kategorier som
   trenger fokus. Default (ingen variant-klasse) beholder hvit surface
   (anonym info). Bruker --icon-{color}-soft-tokens så dark-mode følger. */
.info-bar.info-bar-warning {
    border-left-color: var(--icon-amber);
    background: var(--icon-amber-soft);
}
.info-bar.info-bar-danger {
    border-left-color: var(--icon-red);
    background: var(--icon-red-soft);
}
.info-bar.info-bar-info {
    border-left-color: var(--icon-blue);
    background: var(--icon-blue-soft);
}
.info-bar.info-bar-info .info-bar-icon { color: var(--icon-blue); }

/* Klikkbar (role="button") — cursor + subtle hover. Hover på tintede
   varianter beholder tinten + legger på shadow så kategori-fargen ikke
   flater ut til shade-1. */
.info-bar[role="button"] {
    cursor: pointer;
    transition: background 0.1s, box-shadow 0.1s;
}
.info-bar[role="button"]:hover { background: var(--shade-1); }
.info-bar[role="button"]:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}
.info-bar[role="button"].info-bar-warning:hover {
    background: var(--icon-amber-soft);
    box-shadow: var(--shadow);
}
.info-bar[role="button"].info-bar-danger:hover {
    background: var(--icon-red-soft);
    box-shadow: var(--shadow);
}

/* Tidligere/utløpt-rader noe nedtonet — fortsatt lesbare, mindre fokus. */
.info-bar.is-previous { opacity: 0.85; }

/* Liten muted pille for status-tags inne i info-bar-head ("Arkivert",
   "Utløpt"). Generisk; kan brukes andre steder hvor en tag-pille trengs. */
.tag-pill {
    display: inline-flex;
    align-items: center;
    padding: 0.1rem 0.5rem;
    border-radius: 999px;
    font-size: 0.7rem;
    font-weight: 500;
    background: var(--shade-2);
    color: var(--muted);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.tag-pill-success { background: var(--icon-green-soft); color: var(--icon-green); }
.tag-pill-warning { background: var(--icon-amber-soft); color: var(--icon-amber); }
.tag-pill-danger  { background: var(--icon-red-soft);   color: var(--icon-red); }

/* ------ Announcement-detail-modal ------
   Brukes av views/announcement-detail-modal.js for full visning av en
   announcement. Layout-only — surface kommer fra modal-komponenten. */
.announcement-detail-modal { padding: 0; }
.announcement-detail-meta {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
    margin-bottom: 1rem;
    font-size: 0.85rem;
}
.announcement-detail-content { line-height: 1.55; }
.announcement-detail-content p:first-child { margin-top: 0; }
.announcement-detail-content p:last-child { margin-bottom: 0; }

/* Generisk seksjons-tittel for delte-lister (f.eks. "Aktive" + "Tidligere"
   på /announcements-siden). Ingen domain-prefiks så kan gjenbrukes. */
.list-section + .list-section { margin-top: 2.25rem; }
.list-section-title {
    font-size: 1.05rem;
    font-weight: 600;
    color: var(--fg);
    margin: 0 0 0.5rem;
}
.list-section-title .muted { font-weight: 400; font-size: 0.85rem; }

/* Banner-blokk på brukerportalens dashboard. Trenger luft til tile-
   radene som følger under. */
.dashboard-announcements { margin-bottom: 2rem; }
.dashboard-announcements .section-head { margin-bottom: 0.75rem; }
/* Cart-reminder over tiles på /. Amber så blikket fanges, samme
   info-bar-warning-pattern som driftsmeldinger bruker. */
.dashboard-cart-reminder { margin-bottom: 1.25rem; }

/* ------ Min profil (/me) ------ */
.me-photo-section {
    display: flex;
    gap: 1.5rem;
    align-items: center;
    margin: 1.5rem 0 2rem;
    padding: 1rem;
}
.me-photo img {
    width: 96px;
    height: 96px;
    border-radius: 50%;
    object-fit: cover;
    border: 2px solid var(--border);
}
.me-photo .avatar-lg {
    width: 96px;
    height: 96px;
    font-size: 2rem;
    font-weight: 600;
    background: var(--shade-1);
    color: var(--muted);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
}
.me-photo-actions {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    flex: 1;
}
.me-photo-actions .btn {
    align-self: flex-start;
    cursor: pointer;
}
.me-photo-hint { margin: 0.25rem 0 0; font-size: 0.85rem; }
.me-form {
    display: grid;
    gap: 1rem;
    margin-top: 1rem;
}
.me-form label {
    display: grid;
    gap: 0.3rem;
}
.me-form label > span { font-weight: 600; color: var(--fg); font-size: 0.95rem; }
.me-form .me-hint { font-weight: 400; font-size: 0.8rem; color: var(--muted); margin-top: 0.2rem; }
.me-readonly input { background: var(--shade-1); color: var(--muted); cursor: not-allowed; }
.me-actions { display: flex; justify-content: flex-end; margin-top: 0.5rem; }

/* ------ /me — Settings section ------
   Lives below the profile form. Contains dark-mode toggle, Varslinger,
   Til agent-portal, and Logg ut. On mobile this is the only place
   users can reach these actions, since the topbar avatar-dropdown is
   hidden in that viewport.

   Settings rows have no secondary text, so we override the default
   2-row `.list-item` grid to a single row with three slots:
   icon | primary | tail. Without this the chevron/toggle would land
   in row 2 while the primary text sits in row 1 — visibly off-line. */
.me-settings { margin-top: 2.5rem; }
.me-settings h2 { margin-bottom: 1rem; }
.me-settings .list-item {
    grid-template-columns: auto 1fr auto;
    grid-template-areas: "icon primary tail";
    row-gap: 0;
}
.me-settings .list-item-tail {
    display: inline-flex;
    align-items: center;
    color: var(--muted);
}
/* The toggle row isn't a clickable surface as a whole — disable the
   hover-lift inherited from `.surface`, which would otherwise signal
   "click me" incorrectly. */
.me-setting-static { cursor: default; }
.me-setting-static:hover {
    border-color: var(--border);
    box-shadow: var(--shadow-sm);
    color: var(--fg);
    transform: none;
}
.me-logout-row { margin-top: 1.5rem; display: flex; justify-content: flex-end; }

/* Mobile: photo + actions can't fit in 320-375px next to a 96px avatar +
 * the "Last opp nytt bilde" button, so wrap the section. The button sits
 * below the avatar and gets full row width. Without this the layout
 * viewport silently exceeds the visual viewport, dragging horizontal
 * scroll into the page and pushing the fixed bottom-nav under the
 * mobile browser chrome. */
@media (max-width: 600px) {
    .me-photo-section { flex-wrap: wrap; }
    .me-photo-actions { width: 100%; }
}

/* ------ Fagansvarlige (/fagansvarlige) ------ */
.fa-managers {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem 1.25rem;
    font-size: 0.9rem;
}
.fa-manager {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    white-space: nowrap;
}
.fa-role-badge {
    font-size: 0.7rem;
    font-weight: 600;
    padding: 0.1rem 0.4rem;
    border-radius: var(--radius);
    background: var(--shade-1);
    color: var(--muted);
}
.fa-role-regional { background: #efe6ff; color: #7b4bd6; }
.fa-contact {
    color: var(--muted);
    text-decoration: none;
    padding: 0.15rem 0.3rem;
}
.fa-contact:hover { color: var(--accent); }

/* ------ Feedback form (/helpdesk/feedback/:dep/:id) ------ */
.feedback-form { margin-top: 1.5rem; display: grid; gap: 1.25rem; }
.feedback-rating {
    border: 0;
    padding: 0;
    margin: 0;
    display: grid;
    gap: 0.4rem;
}
.feedback-rating legend {
    padding: 0;
    font-weight: 600;
    color: var(--fg);
    font-size: 0.95rem;
}
.feedback-stars {
    display: flex;
    gap: 0.25rem;
    direction: rtl;       /* so :checked~siblings styling works left-to-right visually */
    justify-content: flex-end;
}
.feedback-star {
    position: relative;
    width: 2rem;
    height: 2rem;
    cursor: pointer;
    color: #d0d4d8;
    font-size: 1.6rem;
}
@media (max-width: 600px) {
    /* iOS minimum tap target: 44x44. Star icon stays at 1.6rem; surface
     * grows around it. 5 stars × 44 + gaps still fits a 320px viewport. */
    .feedback-star { width: 44px; height: 44px; }
}
.feedback-star input {
    position: absolute;
    opacity: 0;
    width: 100%;
    height: 100%;
    cursor: pointer;
    margin: 0;
}
.feedback-star .fas { display: none; }
.feedback-star:hover,
.feedback-star:hover ~ .feedback-star,
.feedback-star:has(input:checked),
.feedback-star:has(input:checked) ~ .feedback-star {
    color: #f5a623;
}
.feedback-star:hover .fas,
.feedback-star:hover ~ .feedback-star .fas,
.feedback-star:has(input:checked) .fas,
.feedback-star:has(input:checked) ~ .feedback-star .fas {
    display: inline;
}
.feedback-star:hover .fal,
.feedback-star:hover ~ .feedback-star .fal,
.feedback-star:has(input:checked) .fal,
.feedback-star:has(input:checked) ~ .feedback-star .fal {
    display: none;
}
.feedback-checkbox {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}
.feedback-actions {
    display: flex;
    gap: 0.75rem;
    justify-content: flex-end;
}

/* ------ Notification preferences (/me/notifications/preferences) ------
 * Card-list layout. Each row carries its own per-channel labels (E-post /
 * Push) — no shared table-header — so the layout reads identically on
 * desktop and mobile. Surface tokens come from the .surface utility on
 * each <li>; rules below are structure only. */
.prefs-form { margin-top: 1.5rem; }
.prefs-list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: grid;
    gap: 0.5rem;
}
.prefs-row {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 1rem;
    align-items: center;
    padding: 0.75rem 1rem;
}
.prefs-row-title { font-weight: 500; }
.prefs-row-channels {
    display: flex;
    gap: 1.25rem;
}
.prefs-channel {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    cursor: pointer;
    color: var(--muted);
    font-size: 0.9rem;
}
.prefs-channel input[type="checkbox"] {
    width: 1.15rem;
    height: 1.15rem;
    cursor: pointer;
    accent-color: var(--accent);
}
.prefs-actions {
    display: flex;
    justify-content: flex-end;
    margin-top: 1rem;
}

@media (max-width: 600px) {
    .prefs-row {
        grid-template-columns: 1fr;
        gap: 0.5rem;
    }
    .prefs-row-channels { gap: 1.5rem; }
}

/* ------ Button system ------
   Single base .btn + colour variants + size/shape modifiers.
   Works identically on <button> and <a> — opt-in via .btn class.
   Bare <button> stays unstyled so component-specific buttons
   (.user-menu-trigger, .nav-icon, .agent-ticket-quickview, etc.)
   don't have to fight a global default.
   See docs/design.md §Buttons. */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    box-sizing: border-box;
    height: 38px;
    padding: 0 1rem;
    font-size: 0.9rem;
    font-family: inherit;
    font-weight: 600;
    color: #fff;
    background: var(--accent);
    border: 1px solid transparent;
    border-radius: var(--radius);
    text-decoration: none;
    cursor: pointer;
    white-space: nowrap;
    transition: background 0.12s, color 0.12s, border-color 0.12s, box-shadow 0.12s;
}
/* No base :hover — each variant defines its own. A previous base rule
   used --link-hover (a *text*-link token that lightens in dark mode),
   which destroyed contrast on solid white-text buttons in dark mode.
   The base also out-specificity'd .btn-ghost:hover via :not(:disabled)
   :not([disabled]), so Cancel buttons got primary-blue hover. Both
   bugs fixed by deleting the base hover. */
.btn:disabled { opacity: 0.6; cursor: not-allowed; }

/* Colour variants — ONLY colour + border, nothing else. */
.btn-primary { background: var(--accent); color: #fff; border-color: transparent; }
.btn-primary:hover { background: var(--btn-primary-hover); color: #fff; }

.btn-success { background: var(--icon-green); color: #fff; border-color: transparent; }
.btn-success:hover { background: #0ea671; color: #fff; }

.btn-danger { background: var(--icon-red); color: #fff; border-color: transparent; }
.btn-danger:hover { background: #c92b2b; color: #fff; }

/* Neutral / ghost — used for toolbar, cancel, secondary actions. */
.btn-ghost {
    background: var(--surface);
    color: var(--fg);
    border-color: var(--border-strong);
}
.btn-ghost:hover {
    background: var(--shade-1);
    border-color: var(--accent);
    color: var(--accent);
}

/* Compact icon-only button (32x32 square with FA-glyph). Brukes der
   en handling trenger sin egen knapp men ikke har plass til tekst:
   per-rad-handlinger i dense tabeller, cart-line-trash, attachment-
   delete osv. Variant `.btn-icon-danger` flipper hover til rødt
   for destruktive handlinger. Tidligere kun definert i agent.css —
   flyttet hit så user-portal (handlekurv mm) også får styling. */
.btn-icon-ghost {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    padding: 0;
    background: transparent;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    color: var(--muted);
    cursor: pointer;
    transition: color 0.12s, border-color 0.12s, background 0.12s;
}
.btn-icon-ghost:hover { color: var(--accent); border-color: var(--accent); }
.btn-icon-ghost.btn-icon-danger:hover { color: var(--icon-red); border-color: var(--icon-red); }
.btn-icon-ghost:disabled { opacity: 0.5; cursor: not-allowed; }

/* Shape modifier: square icon-only button. */
.btn-icon { width: 38px; padding: 0; }

/* Size modifier: small (e.g. inline row actions). */
.btn-sm { height: 30px; padding: 0 0.75rem; font-size: 0.85rem; }
.btn-sm.btn-icon { width: 30px; padding: 0; }

/* Active toggle (e.g. filter button when a filter is applied). */
.btn-ghost.active,
.btn-ghost[aria-pressed="true"] {
    background: var(--icon-blue-soft);
    border-color: var(--accent);
    color: var(--accent);
}

/* `.link-button` — a `<button>` styled to look like a link. Use when
   the action is functionally a button (opens modal/drawer/dialog,
   triggers a mutation) but visually should be low-profile. Accent
   colour, no border/background, underline on hover. See
   `docs/components/button.md` for usage rules. Lived in agent.css
   originally; moved here so the user-portal can use it too. */
.link-button {
    background: transparent;
    border: 0;
    padding: 0;
    color: var(--accent);
    font-size: 0.85rem;
    font-family: inherit;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
}
.link-button:hover { text-decoration: underline; }
/* Hint variant — even more muted, sized like form-help-text. Used as
   a hint-action inline under input fields. */
.link-button-hint {
    margin-top: 0.3rem;
    font-size: 0.78rem;
    color: var(--muted);
    align-self: flex-start;
}
.link-button-hint:hover { color: var(--accent); }

/* Inline count-pill — accent-colored circle showing how many filter
   items are applied. Lives inside .btn (filter-button) so it inherits
   the button's vertical alignment. */
.filter-count-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.4rem;
    height: 1.4rem;
    padding: 0 0.4rem;
    margin-left: 0.35rem;
    border-radius: 999px;
    background: var(--accent);
    color: #fff;
    font-size: 0.78rem;
    font-weight: 700;
    line-height: 1;
}

/* ------ Login page ------ */
.login-layout main#app {
    max-width: 420px;
    margin-top: 10vh;
}

/* ------ Drawer (right-side slide-in panel) ------
   No backdrop: page behind stays interactive. Multiple drawers stack by
   z-index; a floating navigator lists open ones so you can re-surface
   one that's buried. See components/drawer.js. */
.drawer-panel {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    width: var(--drawer-width, 360px);
    max-width: 100vw;
    background: var(--surface);
    box-shadow: -8px 0 24px rgba(0, 0, 0, 0.12);
    transform: translateX(100%);
    transition: transform 0.2s;
    z-index: 200;
    display: flex;
    flex-direction: column;
    border-left: 1px solid var(--border);
}
.drawer-panel.open { transform: translateX(0); }

/* Drag-handle på venstre kant — 6px invisible hit-zone sentrert på borderen.
   Cursor col-resize er visuell cue. Drag-resize håndteres av
   components/resizable.js via Drawer.open(). */
.drawer-resize {
    position: absolute;
    top: 0;
    left: -3px;
    bottom: 0;
    width: 6px;
    cursor: col-resize;
    background: transparent;
    z-index: 1;
    touch-action: none;
}
@media (max-width: 600px) {
    /* På smale skjermer tar drawer-en hele viewporten (max-width: 100vw);
       drag gir lite mening og kan bare føre til forvirrende clamping. */
    .drawer-resize { display: none; }
}

/* ------ ComboSearch (search-as-you-type combobox) ------
   Single input field. Dropdown appears ONLY while the user is typing
   (and fetchOptions has returned options). Floating panel portals to
   <body> so it clears any overflow-hidden / transformed ancestors.
   Arrow/Enter keyboard navigation, Esc + outside-click close.
   See components/combo-search.js. */
.combo-search {
    position: relative;
    width: 100%;
}

/* ------ SearchField (single-pick typeahead — select2-stil) ------ */
/* Se components/search-field.md. Én trigger som ser ut som en standard
   <select>: current value + chevron. Klikk → combobox åpnes (via
   ComboSearch) med søkefelt + liste. Inline × fjerner valgt verdi. */
.search-field {
    width: 100%;
}
.search-field-trigger {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0.65rem 0.5rem 0.8rem;
    background: var(--surface);
    color: var(--fg);
    font: inherit;
    text-align: left;
    /* Surface-tokens + border/radius defineres selv her (IKKE i CANONICAL
       ROW-SURFACE) fordi dette er et input-lignende kontroll-felt med
       samme stil som native <select>/<input>. Border er --border-strong
       per design.md §Borders (actionable UI krever 3:1 kontrast). */
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
    cursor: pointer;
    min-height: 36px;
    transition: border-color 0.15s, outline-color 0.15s;
}
/* Focus-ring matcher den globale input/select-regelen (linje ~1598)
   så <select>, <input> og SearchField-trigger ser identiske ut når
   de står ved siden av hverandre (sidebar, admin-form-cascade osv.). */
.search-field-trigger:hover,
.search-field-trigger:focus-visible {
    outline: 2px solid rgba(54, 150, 252, 0.4);
    outline-offset: 0;
    border-color: var(--accent);
}
.search-field-trigger-text {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.search-field-trigger-tail {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    flex-shrink: 0;
}
.search-field-trigger-chevron {
    color: var(--muted);
    font-size: 0.8rem;
}
.search-field-trigger-clear {
    padding: 0.15rem 0.35rem;
    margin: -0.15rem 0;
    background: transparent;
    border: 0;
    color: var(--muted);
    border-radius: var(--radius);
    cursor: pointer;
    font-size: 0.85rem;
    line-height: 1;
}
.search-field-trigger-clear:hover,
.search-field-trigger-clear:focus-visible {
    color: var(--danger);
    background: rgba(229, 35, 32, 0.08);
    outline: none;
}
/* Trigger-state når popover er åpen: chevron roteres opp. */
.search-field.is-open .search-field-trigger-chevron {
    transform: rotate(180deg);
}
.search-field.is-open .search-field-trigger {
    border-color: var(--accent);
    outline: 2px solid rgba(54, 150, 252, 0.4);
    outline-offset: 0;
}
/* Popover som portales til <body> under triggeren. ComboSearch monteres
   inne med portalPanel:false slik at input + resultatliste er én
   sammenhengende dropdown. */
.search-field-popover {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.10);
    padding: 0.35rem;
    max-height: 360px;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}
/* ComboSearch-feltet inne i popoveren: ingen egen border — popoveren er
   beholderen. Bunnen får en subtle divider mot resultatlista. */
.search-field-popover .combo-search-field {
    border: 0;
    padding: 0 0.25rem;
    border-bottom: 1px solid var(--border);
    border-radius: 0;
    margin-bottom: 0.25rem;
}
.search-field-popover .combo-search-field:focus-within {
    border: 0;
    border-bottom: 1px solid var(--accent);
    box-shadow: none;
}
/* Resultatpanelet er inline (portalPanel:false). Scroller ved overflow. */
.search-field-popover .combo-search-panel {
    border: 0;
    box-shadow: none;
    padding: 0;
    flex: 1;
    min-height: 0;
    overflow-y: auto;
}
.combo-search-field {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    width: 100%;
    padding: 0 0.75em;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    cursor: text;
}
.combo-search-field:focus-within {
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--icon-blue-soft);
}
.combo-search-icon { color: var(--muted); font-size: 0.85rem; flex-shrink: 0; }
/* The input must NOT show its own border/outline because the wrapper
   `.combo-search-field` owns the focus-ring (border + box-shadow on
   :focus-within). Specificity has to beat `.admin-form input[type="search"]`
   (0-2-1) — adding both `.combo-search` and `.combo-search-field` to the
   chain bumps us to 0-3-1 so the picker styles cleanly inside admin-forms. */
.combo-search .combo-search-field input.combo-search-input {
    flex: 1;
    min-width: 0;
    height: auto;
    padding: 0.55em 0;
    border: 0;
    border-radius: 0;
    background: transparent;
    font-family: inherit;
    font-size: 0.95rem;
    color: var(--fg);
}
.combo-search .combo-search-field input.combo-search-input:focus {
    outline: none;
    border: 0;
    box-shadow: none;
}
.combo-search-input::-webkit-search-cancel-button { cursor: pointer; }

/* Floating panel (portaled to <body> when open). */
.combo-search-panel {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    padding: 0.25rem;
    max-height: 360px;
    overflow-y: auto;
}
.combo-search-panel-floating {
    /* Above modal (z-index 400) and drawer-nav (300). */
    z-index: 500;
}
.combo-search-results {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
}
.combo-search-item {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.45rem 0.55rem;
    border-radius: var(--radius);
    cursor: pointer;
    transition: background 0.08s, color 0.08s;
}
.combo-search-item:hover,
.combo-search-item.active { background: var(--icon-blue-soft); color: var(--accent); }
/* Two-line item layout: optional avatar left, name (primary) stacked
   on top of a secondary line like an email or phone. */
.combo-search-item-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
    flex: 1;
    line-height: 1.25;
}
.combo-search-item-primary {
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 0.9rem;
}
.combo-search-item-secondary {
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 0.78rem;
}
.combo-search-item-avatar { flex-shrink: 0; }
.combo-search-empty { padding: 0.5rem 0.75rem; font-size: 0.85rem; }

/* ------ Event list (Sakshistorikk drawer) ------
   Each row is a collapsible .event-item. The button (.event-toggle)
   is the clickable header; .event-detail underneath holds the
   decoded event_data. */
.event-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 0.3rem; }
.event-item {
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    font-size: 0.9rem;
    overflow: hidden;
}
.event-item.expanded { border-color: var(--accent); }
.event-toggle {
    width: 100%;
    display: block;
    padding: 0.55rem 0.75rem;
    background: transparent;
    border: 0;
    text-align: left;
    cursor: pointer;
    position: relative;
    color: var(--fg);
}
.event-toggle:hover { background: var(--shade-1); }
.event-head { display: flex; justify-content: space-between; align-items: baseline; gap: 0.5rem; padding-right: 1.5rem; }
.event-type { font-weight: 600; }
.event-actor { margin-top: 0.2rem; font-size: 0.85rem; }
.event-chevron {
    position: absolute;
    right: 0.75rem;
    top: 50%;
    transform: translateY(-50%);
    color: var(--muted);
    transition: transform 0.15s;
}
.event-item.expanded .event-chevron { transform: translateY(-50%) rotate(180deg); }
.event-detail {
    padding: 0.5rem 0.75rem 0.75rem;
    border-top: 1px dashed var(--border);
    background: var(--shade-1);
}
.event-detail-grid { margin: 0; display: flex; flex-direction: column; gap: 0.35rem; }
.event-row { display: flex; gap: 0.75rem; font-size: 0.85rem; }
.event-row dt { min-width: 120px; flex-shrink: 0; color: var(--muted); font-weight: 600; text-transform: uppercase; font-size: 0.7rem; letter-spacing: 0.05em; padding-top: 0.15rem; }
.event-row dd { margin: 0; flex: 1; min-width: 0; word-break: break-word; }
/* Block variant: label sits on its own line and the value (typically a
   JSON <pre>) gets full width. Used when the value won't fit well in
   the narrow side-by-side column. */
.event-row-block { flex-direction: column; gap: 0.3rem; }
.event-row-block dt { padding-top: 0; }
.event-row-block dd { width: 100%; }
.event-json {
    margin: 0;
    padding: 0.5rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    font-size: 0.75rem;
    /* Wrap long lines instead of horizontal scroll — easier to read in
       the narrow drawer. break-word keeps long tokens (URLs, base64,
       HTML blobs) from blowing out the column. */
    white-space: pre-wrap;
    word-break: break-word;
    max-height: 320px;
    overflow-y: auto;
}

/* ------ Share drawer ------ */
.share-section-title {
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    margin: 0 0 0.5rem;
}
.share-current { margin-bottom: 1.25rem; }
.share-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 0.3rem; }
.share-item {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.4rem 0.5rem;
    border-radius: var(--radius);
    background: var(--shade-1);
}
.share-item-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.btn-remove-share {
    width: 28px; height: 28px;
    border: 0;
    background: transparent;
    color: var(--muted);
    cursor: pointer;
    border-radius: 50%;
}
.btn-remove-share:hover { background: var(--surface); color: var(--icon-red); }

/* ------ Modal (centred, with backdrop) ------
   Use for task-focused decisions (Bytt bruker, Del sak, confirms).
   For side-panel-with-ticket-visible semantics, use Drawer instead. */
.modal-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.35);
    opacity: 0;
    transition: opacity 0.15s;
    z-index: 400;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding: 6vh 1rem 1rem;
    overflow-y: auto;
}
.modal-overlay.open { opacity: 1; }
.modal-panel {
    width: 100%;
    max-width: var(--modal-width, 420px);
    background: var(--surface);
    border-radius: var(--radius-lg);
    box-shadow: 0 20px 48px rgba(0, 0, 0, 0.18);
    transform: translateY(-8px);
    opacity: 0;
    transition: transform 0.15s, opacity 0.15s;
    max-height: 88vh;
    overflow-y: auto;
    outline: none;
}
.modal-panel.open { transform: translateY(0); opacity: 1; }
/* Sticky header so the title + close button stay pinned while the
   body scrolls (only matters when content exceeds 88vh). */
.modal-head {
    position: sticky;
    top: 0;
    z-index: 1;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 1rem 1.25rem;
    background: var(--surface);
    border-bottom: 1px solid var(--border);
}
.modal-head h2 { margin: 0; font-size: 1.1rem; font-weight: 600; }
.modal-close {
    width: 32px;
    height: 32px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: 0;
    color: var(--muted);
    border-radius: 50%;
    cursor: pointer;
}
.modal-close:hover { background: var(--shade-1); color: var(--fg); }
.modal-body {
    /* Asymmetrisk padding: mindre på toppen demper opplevd luft mellom
       divider-linjen og første lille label-tekst. UA-marginer på <p>/<h3>
       nulles ut siden de ikke kollapser gjennom padding. */
    padding: 0.6rem 1.25rem 1rem;
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}
.modal-body > *:first-child { margin-top: 0; }

/* ------ Template picker list (inside drawer) ------ */
.template-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 0.25rem; }
.template-item {
    width: 100%;
    text-align: left;
    padding: 0.6rem 0.75rem;
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--radius);
    color: var(--fg);
    font-size: 0.95rem;
    cursor: pointer;
}
.template-item:hover:not(:disabled) { background: var(--shade-1); border-color: var(--border); }
.template-item:disabled { opacity: 0.6; cursor: not-allowed; }
.template-item-title { display: block; }

/* ------ Drawer navigator (floating pill showing open drawers) ------ */
.drawer-nav {
    position: fixed;
    bottom: 1rem;
    /* Plassert tett ved drawerne (som lever i høyre kant). Når en drawer er
       pinned (body får padding-right), følger nav-en med innover slik at den
       fortsatt sitter rett venstre for drawer-en. */
    right: calc(var(--pinned-drawer-width, 0px) + 1rem);
    z-index: 300;
    transition: right 0.2s;
}
.drawer-nav-toggle {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    height: 40px;
    padding: 0 0.9rem;
    background: var(--fg);
    color: var(--surface);
    border: 0;
    border-radius: 999px;
    box-shadow: var(--shadow);
    cursor: pointer;
    font-weight: 600;
    font-size: 0.9rem;
}
.drawer-nav-toggle:hover { background: var(--accent); color: #fff; }
.drawer-nav-count {
    min-width: 22px;
    height: 22px;
    padding: 0 6px;
    background: var(--accent);
    color: #fff;
    border-radius: 999px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 0.75rem;
}
.drawer-nav-toggle:hover .drawer-nav-count { background: rgba(255, 255, 255, 0.25); }
.drawer-nav-menu {
    position: absolute;
    bottom: calc(100% + 0.5rem);
    right: 0;
    min-width: 260px;
    max-width: 360px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    padding: 0.4rem;
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
}
.drawer-nav-item {
    display: flex;
    align-items: center;
    gap: 0.3rem;
    border-radius: var(--radius);
    transition: background 0.1s;
}
.drawer-nav-item:hover { background: var(--shade-1); }
.drawer-nav-item.active { background: var(--icon-blue-soft); }
.drawer-nav-item.active .drawer-nav-open { color: var(--accent); }
.drawer-nav-open {
    flex: 1;
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.5rem 0.6rem;
    background: transparent;
    border: 0;
    color: var(--fg);
    font-size: 0.9rem;
    text-align: left;
    cursor: pointer;
    min-width: 0;
}
.drawer-nav-open span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}
.drawer-nav-open i { color: var(--muted); width: 1.1em; text-align: center; }
.drawer-nav-close {
    width: 28px;
    height: 28px;
    margin-right: 0.3rem;
    background: transparent;
    border: 0;
    color: var(--muted);
    border-radius: 50%;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.drawer-nav-close:hover { background: var(--shade-2); color: var(--icon-red); }

.drawer-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 1rem 1.25rem;
    border-bottom: 1px solid var(--border);
    gap: 0.5rem;
}
.drawer-head h2 {
    margin: 0;
    font-size: 1.1rem;
    font-weight: 600;
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.drawer-head-actions {
    display: flex;
    align-items: center;
    gap: 0.15rem;
    flex-shrink: 0;
}
.drawer-close,
.drawer-pin,
.drawer-action {
    background: transparent;
    border: 0;
    color: var(--muted);
    width: 32px;
    height: 32px;
    border-radius: 50%;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    text-decoration: none;
}
.drawer-close:hover,
.drawer-pin:hover,
.drawer-action:hover { background: var(--shade-1); color: var(--fg); }
/* Pinned-state — blå, lett tinted bg, og roter pin-en 45° så det er visuelt
   tydelig at den er aktiv (samme grep som standard pinning-UI). */
.drawer-pin.is-active {
    color: var(--accent);
    background: var(--icon-blue-soft);
}
.drawer-pin.is-active i { transform: rotate(-45deg); }

.drawer-body {
    flex: 1;
    overflow-y: auto;
    padding: 1rem 1.25rem;
    /* Plass under siste innhold så drawer-nav-pillen (bottom-right, z 300)
       ikke skjuler siste rad i scrollbar lister. */
    padding-bottom: 4.5rem;
}

/* Pin: body får padding på høyre side så page-content shifter til venstre
   for drawer-en. Selve drawer-panel forblir fixed til right:0. */
body.drawer-pinned {
    padding-right: var(--pinned-drawer-width, 0);
    transition: padding-right 0.2s;
}

/* ------ Filter panel (inside drawer) ------
   Collapsible categories via <details>; live-apply on every change so the
   "Bruk filter"-button is gone (handled in agent-ticket-filter.js). */
.filter-form { display: flex; flex-direction: column; gap: 0.25rem; }
.filter-group {
    border-bottom: 1px solid var(--border);
}
.filter-group:last-of-type { border-bottom: 0; }
/* Hide the native disclosure-triangle so we can render our own
   chevron-icon inside the summary. ::-webkit-details-marker is the
   Webkit/Blink way; `list-style: none` covers Firefox + Safari. */
.filter-group > summary { list-style: none; }
.filter-group > summary::-webkit-details-marker { display: none; }
.filter-group-summary {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.55rem 0.25rem;
    cursor: pointer;
    user-select: none;
    color: var(--muted);
    font-size: 0.78rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    border-radius: var(--radius);
    transition: color 0.1s;
}
.filter-group-summary:hover { color: var(--fg); }
.filter-group-chevron {
    transition: transform 0.15s ease;
    font-size: 0.75rem;
    width: 0.75rem;
    text-align: center;
}
.filter-group[open] > summary .filter-group-chevron {
    transform: rotate(90deg);
}
.filter-group-title { flex: 1; }
.filter-items {
    display: flex;
    flex-direction: column;
    gap: 0.05rem;
    padding: 0 0 0.4rem 1rem;
}
.filter-item {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    padding: 0.3rem 0.4rem;
    border-radius: var(--radius);
    cursor: pointer;
    font-size: 0.9rem;
    transition: background 0.1s;
}
.filter-item:hover { background: var(--shade-1); }
.filter-item input[type="checkbox"],
.filter-item input[type="radio"] {
    accent-color: var(--accent);
    cursor: pointer;
    flex-shrink: 0;
}
.filter-item-label { flex: 1; color: var(--fg); }
.filter-item-count {
    color: var(--muted);
    font-size: 0.8rem;
    font-variant-numeric: tabular-nums;
}
.filter-empty { padding: 0.3rem 0.4rem; font-size: 0.85rem; }
.filter-footer-hint { font-size: 0.78rem; }

.drawer-footer {
    display: flex;
    gap: 0.5rem;
    justify-content: space-between;
    padding: 1rem 1.25rem;
    border-top: 1px solid var(--border);
    background: var(--surface);
}

.btn-o365 {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.75rem;
    padding: 0.75rem 1rem;
    background: var(--surface);
    color: var(--fg);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    font-weight: 600;
    text-decoration: none;
    margin-top: 1.5rem;
    transition: border-color 0.15s, box-shadow 0.15s;
}
.btn-o365:hover {
    border-color: var(--accent);
    box-shadow: var(--shadow-sm);
    color: var(--fg);
}

.login-divider {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin: 1.25rem 0 0;
    color: var(--muted);
    font-size: 0.85rem;
}
.login-divider::before, .login-divider::after {
    content: '';
    flex: 1;
    height: 1px;
    background: var(--border);
}

/* ------ Breadcrumbs ------ */
.breadcrumbs {
    margin: 0.5rem 0 0.75rem;
    font-size: 0.9rem;
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    align-items: center;
}
.breadcrumbs .sep { color: var(--muted); }
.breadcrumbs .current { color: var(--muted); }

/* ------ Ticket detail (main + sidebar layout) ------ */
.ticket-title { margin: 0.25rem 0 1rem; }

.ticket-layout {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1rem;
    padding-bottom: 4rem;
}
@media (min-width: 960px) {
    .ticket-layout {
        grid-template-columns: 1fr 320px;
        gap: 1.5rem;
        align-items: start;
    }
}

.ticket-main { display: flex; flex-direction: column; gap: 0.5rem; }

/* Feedback (vurdering) block — appears above the comment-form on
   closed tickets within FEEDBACK_WINDOW_DAYS. Three rating-rows + a
   first-time-question + optional textarea + submit. The thank-you
   variant replaces the form in place after submit. */
.feedback-block { padding: 1.1rem 1.25rem; }
.feedback-block-title { margin: 0 0 0.25rem; font-size: 1rem; font-weight: 600; }
.feedback-block-sub { margin: 0 0 1rem; font-size: 0.85rem; }
.feedback-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.5rem 0;
    border-top: 1px solid var(--border);
}
.feedback-row:first-of-type { border-top: 0; padding-top: 0; }
.feedback-row-label { color: var(--fg); font-size: 0.9rem; flex: 1; }
.feedback-firsttime-options { display: flex; gap: 1rem; font-size: 0.9rem; }
.feedback-firsttime-options label { display: inline-flex; align-items: center; gap: 0.3rem; cursor: pointer; }
.feedback-other { flex-direction: column; align-items: stretch; gap: 0.4rem; padding: 0.75rem 0; }
.feedback-other .feedback-row-label { font-size: 0.85rem; color: var(--muted); font-weight: 500; }
.feedback-other textarea {
    width: 100%;
    padding: 0.5rem 0.7rem;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
    background: var(--surface);
    color: var(--fg);
    font: inherit;
    font-size: 0.9rem;
    resize: vertical;
    min-height: 4em;
}
.feedback-actions { display: flex; align-items: center; justify-content: flex-end; gap: 1rem; padding-top: 0.5rem; }
.feedback-actions .form-error { color: var(--icon-red); font-size: 0.85rem; flex: 1; margin: 0; }

/* 5-stars rating widget — buttons styled as star-icons. Click sets
   the value, hover previews. Half-stars not exposed (legacy stored
   floats but UI keeps it integer for clarity). */
.rating-stars { display: inline-flex; gap: 0.15rem; }
.rating-star {
    background: transparent;
    border: 0;
    padding: 0.25rem;
    color: var(--muted);
    font-size: 1.25rem;
    cursor: pointer;
    line-height: 1;
}
.rating-star:hover,
.rating-star.rating-star-filled { color: var(--icon-amber); }
.rating-star:focus-visible {
    outline: 2px solid rgba(54, 150, 252, 0.4);
    outline-offset: 2px;
    border-radius: var(--radius);
}

/* Thank-you state shown after submit (and on revisit-with-already-
   submitted). Replaces the form in place. */
.feedback-block-done .feedback-done {
    display: flex;
    align-items: center;
    gap: 0.75rem;
}
.feedback-block-done .feedback-done > i {
    color: var(--icon-green);
    font-size: 1.5rem;
}
.feedback-block-done .feedback-done strong { display: block; font-size: 1rem; }
.feedback-block-done .feedback-done p { margin: 0.15rem 0 0; font-size: 0.85rem; }

/* Reopen-hint above the comment form on closed tickets. */
.ticket-reopen-hint { margin-bottom: 0.5rem; }

/* Ticket-created landing — shown right after a successful submission
   (auto-assigned or pending). Centered card with success icon, title,
   message and action buttons. Confetti fires on mount. */
.ticket-created-card {
    max-width: 540px;
    margin: 3rem auto;
    padding: 2.5rem 2rem;
    text-align: center;
}
.ticket-created-icon {
    color: var(--icon-green);
    font-size: 3rem;
    line-height: 1;
    margin-bottom: 1rem;
}
.ticket-created-title {
    margin: 0 0 0.5rem;
    font-size: 1.4rem;
    font-weight: 600;
}
.ticket-created-message {
    margin: 0 auto 1.5rem;
    max-width: 36ch;
    color: var(--muted);
    line-height: 1.5;
}
.ticket-created-actions {
    display: flex;
    gap: 0.75rem;
    justify-content: center;
    flex-wrap: wrap;
}

/* Closed-ticket chooser — initial state on closed tickets within the
   feedback-window. User picks "Gi tilbakemelding" or "Gjenåpne saken"
   and the corresponding form replaces the chooser in place. The
   wrapper itself has no surface; the two .choice-card-children carry
   their own surface so a wrapping card would read as a comment. */
.closed-chooser { padding: 0.5rem 0; text-align: center; }
.closed-chooser-title { margin: 0 0 0.25rem; font-size: 1rem; font-weight: 600; }
.closed-chooser-sub { margin: 0 0 1rem; font-size: 0.85rem; }
.closed-chooser-options {
    display: grid;
    gap: 0.75rem;
    grid-template-columns: 1fr;
}
@media (min-width: 560px) {
    .closed-chooser-options { grid-template-columns: 1fr 1fr; }
}
.closed-chooser-option {
    display: grid;
    grid-template-columns: 36px 1fr;
    grid-template-areas:
        "icon title"
        "icon sub";
    column-gap: 0.85rem;
    row-gap: 0.15rem;
    align-items: center;
    padding: 1rem 1.1rem;
    text-align: left;
    cursor: pointer;
    color: var(--fg);
    font: inherit;
}
.closed-chooser-option strong { grid-area: title; font-size: 0.95rem; font-weight: 600; }
.closed-chooser-option > span { grid-area: sub; font-size: 0.82rem; }
.closed-chooser-icon {
    grid-area: icon;
    align-self: center;
    font-size: 1.4rem;
    color: var(--accent);
}

/* "Tilbake"-link inside the expanded form — sits at the top of the
   data-closed-footer container so the user can step back to the
   chooser without losing scroll position. */
.closed-footer-back { margin-bottom: 0.5rem; }
.btn-link {
    background: transparent;
    border: 0;
    padding: 0.25rem 0;
    color: var(--accent);
    font: inherit;
    font-size: 0.9rem;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
}
.btn-link:hover { text-decoration: underline; }
.btn-link:focus-visible {
    outline: 2px solid rgba(54, 150, 252, 0.4);
    outline-offset: 2px;
    border-radius: var(--radius);
}
/* Comments live inside [data-comments] (so the append-new-comment flow
   has a stable insertion point). The wrapper itself counts as one
   ticket-main child; the gap only applies to direct children. Mirror
   ticket-main's layout inside the wrapper so individual cards keep the
   same vertical spacing. */
.ticket-main > [data-comments] { display: flex; flex-direction: column; gap: 0.5rem; }
.ticket-sidebar { display: flex; flex-direction: column; gap: 0.75rem; }

.sidebar-card { padding: 1rem 1.25rem; margin: 0; }
.sidebar-label {
    color: var(--muted);
    font-size: 0.8rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    margin-bottom: 0.5rem;
}

/* Slim status indicator — sits at the top of the combined sidebar card,
   before the meta dl. Smaller than a button so it reads as an indicator,
   not a CTA; status icon comes from hd_status.fa_icon. */
.status-stripe {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.45rem 0.75rem;
    border-radius: var(--radius);
    background: var(--pill, #888);
    color: #fff;
    font-weight: 600;
    font-size: 0.9rem;
    margin-bottom: 1rem;
}
.status-stripe i { font-size: 0.85rem; }

.sidebar-meta {
    display: flex;
    flex-direction: column;
    gap: 0.85rem;
    margin: 0;
}
.sidebar-meta-user {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
}
/* Inline-meta avatar — text-sized so it sits in line with the name
   instead of dominating the row. */
.sidebar-meta-user .avatar {
    width: 1.1rem;
    height: 1.1rem;
    font-size: 0.55rem;
}
.sidebar-meta > div { display: flex; flex-direction: column; gap: 0.1rem; }
.sidebar-meta dt {
    color: var(--muted);
    font-size: 0.8rem;
    font-weight: 500;
    margin: 0;
}
.sidebar-meta dd {
    margin: 0;
    color: var(--fg);
    font-weight: 500;
    font-size: 0.95rem;
}

/* ------ New ticket form ------ */
/* Flex-column with row-gap so all direct children — labels, checkboxes,
   the form-error <p>, and the action bar — get uniform vertical spacing.
   Without this, consecutive .checkbox cards (Critical + Confirm) glue
   together with no visual separator. */
.new-ticket-form {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}
.new-ticket-form textarea { resize: vertical; }
.new-ticket-form small { font-size: 0.8rem; }
.required-marker { color: var(--danger); margin-left: 2px; }

/* ------ Fagansvarlige (service-managers directory) ------
   Per service: a section with title + a list of manager rows. Each
   row is a 3-column grid: avatar (lg) / name+role / comm-buttons.
   Surface tokens for `.fa-manager` come from the canonical row-surface
   :is()-block. */
.fa-info { margin-bottom: 1rem; }
.fa-info > span { flex: 1 1 auto; min-width: 0; }
.fa-service { margin-bottom: 2rem; }
.fa-service-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    margin: 0 0 0.5rem;
}
.fa-service-title {
    font-size: 1.1rem;
    font-weight: 600;
    margin: 0;
}
/* Inline link-style action — quieter than .btn-ghost when repeated
   across many service sections. Accent color, underline on hover. */
.fa-service-action {
    background: transparent;
    border: 0;
    padding: 0;
    color: var(--accent);
    font: inherit;
    font-size: 0.9rem;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
}
.fa-service-action:hover { text-decoration: underline; color: var(--link-hover); }
.fa-service-action i { font-size: 0.95em; }

/* Self-service role picker (claim dialog). One radio per role, full-width
   rows with hover-tint so click target is generous. */
.fa-role-options {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    margin-bottom: 1rem;
}
.fa-role-option {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.6rem 0.75rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    cursor: pointer;
}
.fa-role-option:hover { background: var(--shade-1); }
.fa-role-option input { margin: 0; }
.fa-role-option i { color: var(--muted); width: 1.2em; text-align: center; }

/* ------ Page-loader — sentrert "venter på noe"-tilstand som dekker
   hele content-arealet. Brukes av app.js / agent.js mens vi venter på at
   browseren navigerer til OIDC-flyten ved utløpt sesjon (kort vindu, men
   nok til at brukeren rekker å se det). Calm + dempet — ingen rød tekst,
   ingen alarm. Matcher ai-suggest-loading-pattern for ikon-størrelse +
   accent-tint. */
.page-loader {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.9rem;
    min-height: 50vh;
    padding: 3rem 1.5rem;
    color: var(--muted);
    text-align: center;
}
.page-loader-icon {
    font-size: 2rem;
    color: var(--accent);
    line-height: 1;
}
.page-loader-text { margin: 0; font-size: 0.95rem; }

/* ------ Empty-state — full-width centered placeholder when a list has
   no items. Generous whitespace + a calm icon so first-time users notice
   the page at all. Used by my-tickets ("Ingen saker ennå"), can be reused
   anywhere a list is empty. */
.empty-state {
    text-align: center;
    padding: 3rem 1.5rem;
    color: var(--fg);
}
/* Wrapper, not the <i> itself — FA-kit replaces <i> with <svg> at
   runtime, so an `.empty-state-icon i` selector wouldn't match. Set
   font-size + color on the wrapper; both cascade: font-size scales the
   em-sized SVG, color tints currentColor on the glyph. The inner span
   anchors the ambient steam-wisp pseudo-elements (position: relative
   on the wrapper would anchor to the full-width content box, not the
   icon — so we use an inline-block hugger). */
.empty-state-icon {
    text-align: center;
    margin-bottom: 1rem;
    font-size: 3.5rem;
    color: var(--muted);
    line-height: 1;
}
/* "Sip" idle animation — the cup tilts back ~6° as if someone took a
   sip, then settles. Long hold periods on either side so the motion
   only happens roughly every 14 seconds. Tilts around the bottom-right
   (handle side) so the lift looks natural. */
.empty-state-icon-inner {
    display: inline-block;
    transform-origin: 60% 100%;
    animation: empty-state-sip 14s ease-in-out infinite;
}
@keyframes empty-state-sip {
    0%, 86%, 100% { transform: rotate(0deg); }
    91%           { transform: rotate(-6deg); }
    96%           { transform: rotate(0deg); }
}

/* Emoji-variant for dekorative empty-states (no-access, not-found).
   Overrider den default sip-keyframen med en peek-shift som passer
   bedre til 👀/🤔. line-height settes eksplisitt så glyph-en sentreres
   like nøyaktig som en FA-glyph. */
.empty-state-icon-emoji {
    font-size: 2.6rem;
    line-height: 1;
    transform-origin: 50% 50%;
    animation: empty-state-peek 6s ease-in-out infinite;
}
@keyframes empty-state-peek {
    0%, 75%, 100% { transform: translateX(0); }
    82%           { transform: translateX(-5px) rotate(-3deg); }
    90%           { transform: translateX(5px) rotate(3deg); }
}

/* Attention-shake on a primary CTA — used by my-tickets.js when the
   empty-state is showing, to seal the "click here" affordance. Brief
   ±2° wiggle every 7 seconds; mostly still in between so the page
   doesn't feel hectic. Applied via .btn-attention class, removed by
   the next re-render. */
.btn-attention { animation: btn-attention-shake 7s ease-in-out infinite; }
@keyframes btn-attention-shake {
    0%, 90%, 100% { transform: rotate(0deg); }
    92%           { transform: rotate(-2deg); }
    94%           { transform: rotate(2deg); }
    96%           { transform: rotate(-2deg); }
    98%           { transform: rotate(0deg); }
}

@media (prefers-reduced-motion: reduce) {
    .empty-state-icon-inner,
    .btn-attention,
    .confetti-piece { animation: none; }
}

/* Confetti — håndrullet CSS-animasjon, drevet fra helpers/confetti.js.
   Pieces er absolute i .confetti-layer (som er absolute relativt til
   nærmeste positioned ancestor — typisk drawer.body eller document.body
   for full-viewport). Hver piece faller fra topp med horizontal drift +
   rotasjon, fader ut nederst. Brukes både fra agent-portalen og
   bruker-portalen så lever her i main.css i stedet for agent.css. */
.confetti-layer {
    position: absolute;
    inset: 0;
    pointer-events: none;
    overflow: hidden;
    z-index: 1;
}
.confetti-piece {
    position: absolute;
    top: -16px;
    width: 8px;
    height: 14px;
    border-radius: 1px;
    /* Defaults — overstyres per piece via inline custom properties
       satt fra JS (CSS leser dem via var()). */
    --c-left: 50%;
    --c-bg: var(--accent);
    --c-delay: 0s;
    --c-duration: 2s;
    --confetti-drift: 0%;
    --confetti-rotate-start: 0deg;
    --confetti-rotate-end: 360deg;
    left: var(--c-left);
    background: var(--c-bg);
    animation: confetti-fall var(--c-duration) linear var(--c-delay) forwards;
    transform: rotate(var(--confetti-rotate-start));
    opacity: 0.9;
}
@keyframes confetti-fall {
    0%   { transform: translate(0, 0) rotate(var(--confetti-rotate-start)); opacity: 1; }
    80%  { opacity: 1; }
    100% { transform: translate(var(--confetti-drift), calc(100vh + 40px)) rotate(var(--confetti-rotate-end)); opacity: 0; }
}

/* ---- Pending-row affordance + forklarings-modal ---- */
/* Pending-saker har ikke saksnummer enda så de kan ikke routes — i
   stedet er hele raden klikkbar og åpner en forklarings-modal. .list-
   item-explain markerer "klikk for forklaring" for både .list-item-
   pending (helpdesk-saker) og evt. fremtidige liknende rader. */
.list-item.list-item-explain {
    cursor: help;
    transition: background 0.12s, border-color 0.12s;
}
.list-item.list-item-explain:hover {
    background: var(--surface-2);
    border-color: var(--accent);
}
.list-item.list-item-explain:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: -2px;
}

.pending-explain p { margin: 0 0 0.75rem; line-height: 1.45; }
.pending-explain-meta {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: 0.4rem 0.9rem;
    margin: 1rem 0 0;
    padding: 0.7rem 0.9rem;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: 8px;
    font-size: 0.88rem;
}
.pending-explain-meta dt { color: var(--muted); }
.pending-explain-meta dd { margin: 0; font-weight: 500; }

.empty-state-title {
    margin: 0 0 0.5rem;
    font-size: 1.25rem;
    font-weight: 600;
}
.empty-state-body {
    max-width: 480px;
    margin: 0 auto 0.5rem;
    color: var(--muted);
    line-height: 1.5;
}
.empty-state-quip {
    max-width: 480px;
    margin: 1rem auto 0;
    color: var(--muted);
    font-size: 0.85rem;
    font-style: italic;
}

.fa-managers { margin: 0; }
.fa-manager {
    display: grid;
    grid-template-columns: auto 1fr auto;
    align-items: center;
    column-gap: 1rem;
    padding: 0.75rem 1rem;
    min-height: 64px;
}
.fa-manager-avatar { display: flex; }
.fa-manager-data { min-width: 0; }
.fa-manager-name { font-weight: 600; }
.fa-manager-role {
    font-size: 0.85rem;
    margin-top: 0.15rem;
    display: flex;
    align-items: center;
    gap: 0.4rem;
}
.fa-manager-comm {
    display: flex;
    gap: 0.5rem;
    flex-shrink: 0;
}
.fa-comm-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    color: var(--muted);
    text-decoration: none;
    transition: background 0.15s, color 0.15s;
}
.fa-comm-btn:hover {
    background: var(--icon-blue-soft);
    color: var(--accent);
}
/* Stack comm-buttons below the manager row on mobile + bump them to
 * 44×44 so they meet the iOS tap-target minimum. Breakpoint matches
 * the user-portal shell (600px). */
@media (max-width: 600px) {
    .fa-manager {
        grid-template-columns: auto 1fr;
        grid-template-areas:
            "avatar data"
            "comm   comm";
        row-gap: 0.5rem;
    }
    .fa-manager-avatar { grid-area: avatar; }
    .fa-manager-data   { grid-area: data; }
    .fa-manager-comm   { grid-area: comm; justify-content: flex-end; }
    .fa-comm-btn { width: 44px; height: 44px; }
}

/* Inputs/selects/textareas inside the create-ticket form must fill the
   label container — otherwise their intrinsic min-content (a select's
   longest option text, an input's ~150px default) overflows the narrow
   sidebar (300px) and the 1fr/2fr Etg+Rom row, pushing the right edge
   past the .sidebar-card border. min-width:0 lets grid cells shrink
   below the input's natural size. */
.new-ticket-form-wrap input:not([type="checkbox"]):not([type="radio"]):not([type="file"]),
.new-ticket-form-wrap select,
.new-ticket-form-wrap textarea {
    width: 100%;
    box-sizing: border-box;
    min-width: 0;
}
.new-ticket-form-wrap label { min-width: 0; }

.new-ticket-layout {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1rem;
}
@media (min-width: 900px) {
    .new-ticket-layout {
        grid-template-columns: 1fr 300px;
        gap: 1.5rem;
        align-items: start;
    }
}
.new-ticket-sidebar .sidebar-card { display: flex; flex-direction: column; gap: 1rem; }

/* Avdelings-spesifikk hjelpetekst over skjemaet (info_content.helptext).
   Egen klasse så padding/margin kan stilles uavhengig av selve skjema-
   kortet. Surface + radius + skygge arves fra .surface-utility i markup. */
.new-ticket-helptext {
    padding: 1rem 1.25rem;
    margin-bottom: 1rem;
}

/* Avdelings-spesifikk footer (info_content.footer_left/mid/right) under
   skjemaet i 3-kol layout — kollapser til 1-kol på mobil. */
.new-ticket-footer {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1.25rem;
    padding: 1.25rem 1.5rem;
    margin-top: 1.25rem;
}
@media (min-width: 720px) {
    .new-ticket-footer { grid-template-columns: repeat(3, 1fr); }
}
/* Tomme kolonner gir tom grid-celle, ikke skjul (ellers krymper de andre
   kolonnene asymmetrisk på desktop). På mobil blir hver tomme div bare
   en 0-høyde-rad — usynlig i praksis. */
/* Two-field row inside a form. Stacks on mobile (each field full-width)
 * so the narrower of the two doesn't shrink to ~40px usable space.
 * Used in create-ticket (Etg + Rom), several agent settings views. */
.form-row { display: grid; grid-template-columns: 1fr 2fr; gap: 0.75rem; }
@media (max-width: 600px) {
    .form-row { grid-template-columns: 1fr; gap: 0.5rem; }
}
.form-actions { display: flex; justify-content: flex-end; margin-top: 0.5rem; }
.form-success {
    margin: 0;
    color: var(--success);
    font-weight: 500;
    padding: 0.75rem 1rem;
    background: var(--icon-green-soft);
    border-radius: var(--radius);
}

/* ------ Comment form ------
   Two layers, matching the old app:
   - .comment-form-card: white card with dashed divider, textarea, clip.
     Border turns red when the private-toggle is on (is-private).
   - .comment-form-footer: row outside the card with error, optional
     solution checkbox, and the Publiser button.
*/
.comment-form { display: block; margin-top: 0.5rem; }

/* Surface arves fra .surface-utility i markup. Her kun struktur. */
.comment-form-card {
    transition: border-color 0.15s;
}
.comment-form-card.is-private { border-color: var(--icon-red); }

.comment-form-top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.75rem 1rem;
    border-bottom: 1px dashed var(--border);
}
.comment-form-recipient { color: var(--muted); font-size: 0.9rem; }
.comment-form-card.is-private .comment-form-recipient { color: var(--icon-red); font-weight: 600; }
.comment-form-top-right {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    color: var(--muted);
}

/* Presence-warning over editoren. Synlig kun når andre lesere er
   inne på saken (refreshReaders fyller / tømmer banneret hvert 20s).
   Amber-tone så det fanger blikket uten å se ut som en feilmelding —
   og den ligger akkurat der agenten skal til å skrive, ikke i topbar
   der det er lett å glemme. Ingen bunn-border (form-body har ingen
   topp-border) så banneret står som ett sammenhengende stykke. */
.comment-form-presence {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.55rem 1rem;
    background: var(--icon-amber-soft);
    color: var(--fg);
    font-size: 0.9rem;
    border-bottom: 1px dashed var(--border);
}
.comment-form-presence > i {
    color: var(--icon-amber);
    font-size: 1rem;
    flex-shrink: 0;
}
.comment-form-presence-avatars {
    display: flex;
    flex-shrink: 0;
}
.comment-form-presence-avatars .presence-avatar {
    width: 22px;
    height: 22px;
    font-size: 0.6rem;
    margin-left: -6px;
    border: 2px solid var(--surface);
    background: var(--accent);
    color: #fff;
}
.comment-form-presence-avatars .presence-avatar:first-child {
    margin-left: 0;
}
/* Overflow-badge — kommer etter cap'et avatar-rad når readers.length
   > PRESENCE_AVATAR_LIMIT. Henter dimensjoner fra .presence-avatar-
   søsken-reglene (i .agent-presence og .comment-form-presence-avatars);
   her overstyrer vi bare bakgrunnen — den er ikke en person, så den
   skal ikke ha accent-fargen. */
.agent-presence .presence-avatar-overflow,
.comment-form-presence-avatars .presence-avatar-overflow {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--shade-2);
    color: var(--fg);
    border-radius: 50%;
}
.comment-form-presence-text {
    flex: 1;
    min-width: 0;
}

.comment-form-body {
    position: relative;
    padding: 0.5rem 0 2.25rem;
}
/* User-portal flow uses an inline FileDropzone instead of the absolutely-
   positioned paperclip — no need for the 2.25rem bottom-reserve. */
.comment-form-body.comment-form-body-flow {
    padding-bottom: 0.5rem;
}
/* Align the inline dropzone with the editor toolbar's internal padding
   so it doesn't sit flush with the card-edge while everything else is
   indented. Margin instead of body-level padding so we don't double-up
   with the toolbar's own internal 0.75rem horizontal padding. */
.comment-form-body-flow > .dropzone {
    margin: 0 0.75rem 0.5rem;
}
.comment-form-body-flow > .comment-form-attachments {
    margin-left: 0.75rem;
    margin-right: 0.75rem;
}
.comment-form-body textarea {
    width: 100%;
    min-height: 110px;
    resize: vertical;
    padding: 0.75rem 1rem;
    border: 0;
    background: transparent;
    font-family: inherit;
    font-size: 0.95rem;
    line-height: 1.5;
    color: var(--fg);
}
.comment-form-body textarea:focus { outline: none; }

/* ------ Rich-text comment editor ------
   Native contenteditable + toolbar. Placeholder via :empty + ::before.
   See components/comment-editor.js for the behaviour. */
.comment-editor-host { position: relative; }
/* Bordered variant — for editor instances that sit in a context without
   a surrounding surface (modal body, plain admin form). Mirrors the
   form-input border + focus-within affordance so the user sees where
   the editable area begins/ends. See design.md §Forms. */
.comment-editor-host.is-bordered {
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
    overflow: hidden;
    background: var(--surface);
    transition: border-color 0.12s, box-shadow 0.12s;
}
.comment-editor-host.is-bordered:focus-within {
    border-color: var(--accent);
    box-shadow: 0 0 0 2px rgba(54, 150, 252, 0.4);
}
.comment-editor-toolbar {
    display: flex;
    align-items: center;
    gap: 0.1rem;
    padding: 0.3rem 0.75rem;
    border-bottom: 1px dashed var(--border);
    color: var(--muted);
}
.ce-btn {
    width: 30px;
    height: 28px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: 0;
    border-radius: var(--radius);
    color: var(--muted);
    cursor: pointer;
    font-size: 0.85rem;
}
.ce-btn:hover { background: var(--shade-1); color: var(--accent); }
/* Text-buttons in the toolbar (H2/H3) — font-awesome has no good icons
   for headings, so we render the label as text and style it a bit
   heavier so it reads as a button. */
.ce-btn-text {
    font-weight: 700;
    font-size: 0.85rem;
    letter-spacing: 0.02em;
    line-height: 1;
}
.ce-sep { width: 1px; height: 18px; background: var(--border); margin: 0 0.25rem; }

.comment-editor {
    min-height: 110px;
    padding: 0.75rem 1rem;
    font-family: inherit;
    font-size: 0.95rem;
    line-height: 1.5;
    color: var(--fg);
    outline: none;
    word-break: break-word;
}
.comment-editor:empty::before {
    content: attr(data-placeholder);
    color: var(--muted);
    pointer-events: none;
}
.comment-editor p { margin: 0 0 0.5em; }
.comment-editor ul, .comment-editor ol { padding-left: 1.25rem; margin: 0 0 0.5em; }
.comment-editor a { color: var(--link); }
/* Pasted images — cap width so a large screenshot doesn't blow out the
   editor / comment column. Same rule applies to .prose-rendered comments
   below so width is consistent between editor preview and final view. */
.comment-editor img,
.prose img,
.comment-system-body img {
    max-width: 100%;
    height: auto;
    display: block;
    border-radius: var(--radius);
    margin: 0.4rem 0;
}
/* Rendered comment-body imgs are click-to-lightbox (handler in
   helpers/attachments.js bindAttachmentClicks). Editor-imgs (still
   composing) stay non-clickable so the user can manipulate them. */
.prose img,
.comment-system-body img {
    cursor: zoom-in;
    transition: opacity 0.12s;
}
.prose img:hover,
.comment-system-body img:hover {
    opacity: 0.92;
}
/* "Vis historikk"-modal — kommentar-versjonshistorikk. Stack med en
   "Aktuell versjon"-kort på toppen og hver tidligere versjon under,
   reverse-chronological. Subtle separator mellom dem så øyet ser at
   de er adskilte snapshots. */
.comment-versions {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}
.comment-version {
    padding: 0.85rem 1rem;
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: var(--surface);
}
.comment-version-current {
    border-color: var(--accent);
    box-shadow: 0 0 0 2px var(--icon-blue-soft);
}
.comment-version-head {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    margin-bottom: 0.6rem;
    font-size: 0.85rem;
}
.comment-version-meta {
    display: flex;
    flex-direction: column;
    line-height: 1.25;
    min-width: 0;
}
.comment-version-meta strong { color: var(--fg); font-size: 0.95rem; }
.comment-version-meta .muted { font-size: 0.8rem; }
.comment-version-body { color: var(--fg); font-size: 0.92rem; }
.comment-versions-empty { margin: 0; font-size: 0.9rem; }

/* Inline placeholder shown while a pasted image is uploading. Replaced
   with the real <img> on success, removed on failure (with a brief
   error notice). */
.rte-img-placeholder {
    display: inline-block;
    padding: 0.25rem 0.6rem;
    margin: 0.2rem 0;
    background: var(--shade-1);
    border: 1px dashed var(--border);
    border-radius: var(--radius);
    color: var(--muted);
    font-size: 0.85rem;
}

/* Mention chip — appears both inside the editor and in rendered comments.
   When rendered in a comment body it's clickable (data-user-id picked up
   by the page-level user-link delegation → opens user-profile-drawer). */
.mention {
    display: inline-block;
    padding: 0 0.35em;
    background: var(--icon-blue-soft);
    color: var(--accent);
    border-radius: 4px;
    font-weight: 600;
    font-size: 0.9em;
    user-select: none;
}
.mention[data-user-id] { cursor: pointer; }
.mention[data-user-id]:hover { background: var(--accent); color: #fff; }

/* Mention autocomplete dropdown */
.mention-dropdown {
    position: absolute;
    z-index: 50;
    min-width: 220px;
    max-width: 340px;
    max-height: 260px;
    overflow-y: auto;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    padding: 0.25rem;
}
.mention-item {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0;
    width: 100%;
    padding: 0.4rem 0.55rem;
    background: transparent;
    border: 0;
    border-radius: var(--radius);
    text-align: left;
    cursor: pointer;
    color: var(--fg);
}
.mention-item:hover,
.mention-item.active { background: var(--icon-blue-soft); color: var(--accent); }
.mention-item-name { font-size: 0.9rem; font-weight: 500; }
.mention-item-mail { font-size: 0.75rem; }
.mention-empty { padding: 0.5rem 0.75rem; font-size: 0.85rem; }

.comment-form-clip {
    position: absolute;
    right: 0.75rem;
    bottom: 0.6rem;
    width: 32px;
    height: 32px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--muted);
    cursor: pointer;
    border-radius: 50%;
    transition: background 0.1s, color 0.1s;
}
.comment-form-clip:hover { background: var(--shade-1); color: var(--accent); }

.comment-form-attachments { margin-top: 0.6rem; }
.comment-form-attachments:empty { display: none; }

.comment-form-footer {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-top: 0.6rem;
    padding: 0 0.25rem;
}
/* Narrow viewports collapse the agent-ticket-main padding-right to 0
 * (so the stacked sidebar can use the full width). That puts the
 * footer's right edge — and therefore the Publiser button — flush
 * against the viewport. Add an explicit horizontal pad on the footer
 * itself so the button has a comfortable margin from the screen edge. */
@media (max-width: 900px) {
    .comment-form-footer { padding: 0 0.75rem; }
}
.comment-form-footer .form-error { margin: 0; }
/* Mal + AI-forslag folded into an ellipsis dropdown so the footer stays
 * compact on every viewport (was two stacked link-buttons taking up
 * row width on desktop and breaking the row on mobile). The timer
 * keeps `margin-left: auto` so it + Publiser anchor to the far right
 * regardless of how much space the dropdown takes on the left. */
.comment-form-extras-trigger {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    padding: 0;
    background: transparent;
    border: 0;
    border-radius: var(--radius);
    color: var(--muted);
    font-size: 1rem;
    cursor: pointer;
}
.comment-form-extras-trigger:hover { background: var(--shade-1); color: var(--accent); }
/* Open upward — the footer sits at the bottom of the form, opening
 * the menu downward would push it past the viewport edge or under
 * the bottom-nav on user-portal. */
.comment-form-extras-menu {
    top: auto;
    bottom: calc(100% + 6px);
    left: 0;
    right: auto;
}
.comment-form-timer {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    margin-left: auto;
    padding: 0.35em 0.6em;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    color: var(--muted);
    font-size: 0.9rem;
}
.comment-form-timer i { color: var(--muted); }
.comment-form-timer input,
.comment-form-timer select {
    width: 62px;
    border: 0;
    background: transparent;
    font-family: inherit;
    font-size: 0.9rem;
    font-variant-numeric: tabular-nums;
    color: var(--fg);
    padding: 0;
    cursor: pointer;
}
.comment-form-timer input { width: 48px; cursor: text; }
.comment-form-timer input:focus,
.comment-form-timer select:focus { outline: none; }
/* On user-side forms without a timer, the button takes the spare space. */
.comment-form-footer:not(:has(.comment-form-timer)) > .btn { margin-left: auto; }

/* "Sett som løst"-checkbox in the user-portal comment-form footer. Only
   shown when the caller is the ticket owner; pairs the comment post with
   a status-flip via /api/hd/mine/ticket/{dep}/{id}/solve. */
.comment-form-solve {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    color: var(--fg);
    font-size: 0.9rem;
    font-weight: 500;
    cursor: pointer;
    user-select: none;
}
.comment-form-solve input[type="checkbox"] { margin: 0; cursor: pointer; }

/* ------ Toggle switch (reusable) ------ */
.toggle-switch {
    position: relative;
    display: inline-block;
    width: 36px;
    height: 20px;
    flex-shrink: 0;
}
.toggle-switch input {
    position: absolute;
    opacity: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    cursor: pointer;
    z-index: 1;
}
.toggle-switch-slider {
    position: absolute;
    inset: 0;
    background: var(--shade-2);
    border-radius: 999px;
    transition: background 0.15s;
}
.toggle-switch-slider::before {
    content: '';
    position: absolute;
    left: 2px;
    top: 2px;
    width: 16px;
    height: 16px;
    background: #fff;
    border-radius: 50%;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
    transition: transform 0.15s;
}
.toggle-switch input:checked ~ .toggle-switch-slider { background: var(--accent); }
.toggle-switch input:checked ~ .toggle-switch-slider::before { transform: translateX(16px); }

/* ------ FA-picker ------
   Reusable Font Awesome icon picker — text input + live preview + grid
   modal. See docs/components/fa-picker.md. */
.fa-picker {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    width: 100%;
    min-width: 0;
}
.fa-picker-preview {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    padding: 0;
    background: var(--shade-1);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
    color: var(--fg);
    font: inherit;
    font-size: 1.1rem;
    cursor: pointer;
    flex-shrink: 0;
    transition: border-color 0.12s, background 0.12s;
}
.fa-picker-preview:hover {
    border-color: var(--accent);
    background: var(--icon-blue-soft);
}
.fa-picker-preview:focus-visible {
    outline: 2px solid rgba(54, 150, 252, 0.4);
    outline-offset: 1px;
    border-color: var(--accent);
}
.fa-picker-input {
    flex: 1 1 auto;
    min-width: 0;
}

.fa-picker-modal-grid {
    max-height: 56vh;
    overflow-y: auto;
    margin-top: 0.5rem;
    padding-right: 0.25rem;
}
.fa-picker-modal-group + .fa-picker-modal-group {
    margin-top: 1rem;
}
.fa-picker-modal-group-title {
    font-size: 0.78rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--muted);
    margin: 0 0 0.5rem 0;
    position: sticky;
    top: 0;
    background: var(--surface);
    padding: 0.25rem 0;
    z-index: 1;
}
.fa-picker-modal-items {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(72px, 1fr));
    gap: 0.4rem;
}
.fa-picker-modal-item {
    aspect-ratio: 1 / 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.35rem;
    padding: 0.5rem 0.35rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    color: var(--fg);
    cursor: pointer;
    font: inherit;
    text-align: center;
    transition: border-color 0.12s, transform 0.12s, background 0.12s;
}
.fa-picker-modal-item:hover {
    border-color: var(--accent);
    transform: translateY(-1px);
}
.fa-picker-modal-item.is-selected {
    border-color: var(--accent);
    background: var(--icon-blue-soft);
}
.fa-picker-modal-item i {
    font-size: 1.4rem;
}
.fa-picker-modal-item-name {
    font-size: 0.7rem;
    color: var(--muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 100%;
    line-height: 1.1;
}
.fa-picker-modal-empty {
    padding: 1rem 0;
    text-align: center;
}

/* ------ Attachment chips ------
   Used in comment bodies (clickable → fetch blob → open in new tab)
   and in the comment form preview (static, before upload). */
.attachment-list {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin-top: 0.75rem;
}
.attachment-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    max-width: 320px;
    height: 32px;
    padding: 0 0.75rem;
    background: var(--shade-1);
    color: var(--fg);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    font-size: 0.85rem;
    cursor: pointer;
    transition: border-color 0.1s, background 0.1s;
}
.attachment-chip:hover { border-color: var(--accent); background: var(--icon-blue-soft); }
.attachment-chip i { color: var(--muted); flex-shrink: 0; }
.attachment-chip:hover i { color: var(--accent); }
.attachment-chip .attachment-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}
.attachment-chip .attachment-size { color: var(--muted); font-size: 0.75rem; flex-shrink: 0; }
.attachment-chip.is-pending { cursor: default; border-style: dashed; background: var(--surface); }
.attachment-chip.is-pending:hover { background: var(--surface); border-color: var(--border); }
.attachment-chip.is-pending i { color: var(--accent); }
.attachment-chip:disabled { opacity: 0.6; cursor: not-allowed; }
.attachment-chip-remove {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: none;
    padding: 0 0 0 0.25rem;
    margin-left: 0.15rem;
    color: var(--muted);
    cursor: pointer;
    font: inherit;
    line-height: 1;
    flex-shrink: 0;
}
.attachment-chip-remove:hover { color: var(--icon-red); }

/* Comment-edit modal: existing-attachments rows. Static layout (no
   click-to-preview — that's for the read view), each row carries an
   X-button for per-file redaction. Sits between the editor and the
   action bar. */
.attachment-edit-list {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    margin-top: 1rem;
}
.attachment-edit-label {
    color: var(--muted);
    font-size: 0.78rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    margin-bottom: 0.25rem;
}
.attachment-edit-row {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.45rem 0.6rem;
    background: var(--shade-1);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    font-size: 0.85rem;
}
.attachment-edit-row i { color: var(--muted); flex-shrink: 0; }
.attachment-edit-row .attachment-name {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}
.attachment-edit-row .attachment-size { color: var(--muted); font-size: 0.75rem; flex-shrink: 0; }
.attachment-edit-remove {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    background: none;
    border: 0;
    border-radius: 50%;
    color: var(--muted);
    cursor: pointer;
    flex-shrink: 0;
}
.attachment-edit-remove:hover { color: var(--icon-red); background: var(--icon-red-soft); }
.attachment-edit-remove:disabled { opacity: 0.5; cursor: not-allowed; }

/* Image-attachment thumbnails — sit alongside chips in the same
   .attachment-list flex-wrap container. Square tile with object-fit:
   cover so different aspect ratios all look uniform. */
.attachment-thumb {
    width: 96px;
    height: 96px;
    padding: 0;
    background: var(--shade-1);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    overflow: hidden;
    cursor: pointer;
    transition: border-color 0.12s, transform 0.12s;
    flex-shrink: 0;
}
.attachment-thumb:hover {
    border-color: var(--accent);
    transform: translateY(-1px);
}
.attachment-thumb:focus-visible {
    outline: 2px solid rgba(54, 150, 252, 0.4);
    outline-offset: 1px;
    border-color: var(--accent);
}
.attachment-thumb-img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* PDF preview modal — iframe with browser-native PDF viewer + a
   "Last ned"-action below. Modal width is set per-call (960px); height
   here is intentional viewport-percent so the iframe gets vertical room. */
.pdf-preview {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    height: 80vh;
}
.pdf-preview-frame {
    flex: 1 1 auto;
    width: 100%;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--shade-1);
}
.pdf-preview-actions {
    display: flex;
    justify-content: flex-end;
    flex-shrink: 0;
}
.form-error {
    margin: 0;
    color: var(--danger);
    font-size: 0.9rem;
    font-weight: 500;
}

/* Prose = HTML content from a ticket body or comment. */
.prose { font-size: 0.95rem; line-height: 1.55; }
.prose img { max-width: 100%; height: auto; }
.prose a { color: var(--link); }
.prose h4 { margin: 0.75em 0 0.25em; font-size: 0.95rem; }
.prose ul, .prose ol { padding-left: 1.25rem; }

/* Comments — each is its own card (same pattern as list-items). */
.comments { display: flex; flex-direction: column; gap: 0.5rem; }
.comments > h2 { margin: 0.5rem 0 0.25rem; }

.comment-card {
    padding: 1rem 1.25rem;
    margin: 0;
}
.comment-head {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 0.6rem;
    font-size: 0.9rem;
}
.comment-author { display: flex; flex-direction: column; line-height: 1.2; }
.comment-author strong { color: var(--fg); font-size: 0.95rem; }
.comment-author .muted { font-size: 0.8rem; }

.avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: var(--icon-blue-soft);
    color: var(--icon-blue);
    font-weight: 600;
    font-size: 0.85rem;
    flex-shrink: 0;
    overflow: hidden;
    position: relative;
}
.avatar img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
.avatar [data-photo-fallback] {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
}

.comment-type-badge {
    /* Badge sits inline next to the username (post-strong, pre-time).
       Old positioning used `margin-left: auto` to push to the row's
       right edge, but that moved <time> leftward only on rows with a
       badge — adjacent timestamps fell out of vertical alignment. */
    padding: 0.2em 0.65em;
    font-size: 0.75rem;
    font-weight: 600;
    border-radius: 999px;
}
.comment-type-solution {
    background: var(--icon-green-soft);
    color: var(--icon-green);
}
.comment-type-private {
    background: var(--icon-amber-soft);
    color: var(--icon-amber);
}
.comment-type-system {
    background: var(--shade-2);
    color: var(--muted);
}

/* NB: variant-styling for comments lives in agent.css, scoped to
   .comment-flat.comment-X so it only applies to the agent-portal's
   flat layout. The user-portal renders comments as
   `<article class="surface comment-card card">` — a different design
   system entirely (the user-portal is intentionally simpler than
   agent). Don't add variant rules here unless you mean both portals
   to share the styling — see design.md §"Two shells: user portal
   vs agent app". */

/* ------ Ticket merchandise summary (user-portal) ------
   Read-only-vareliste under inquery på /helpdesk/{dep}/{id} for saker
   som har varelinjer (typisk "Bestilling av varer fra nettbutikken").
   Agent-portalen har egen Varer-tab med edit-controls; her viser vi
   bare hva som er bestilt + sum, så bruker har same source-of-truth
   som agenten. .ticket-merch-* prefix er NOT i konflikt med
   agent.css' .ticket-merch — agent-CSS lastes ikke i user-portalen. */
.ticket-merch-summary {
    margin-top: 1rem;
    padding: 0.85rem 1rem;
    background: var(--shade-1);
    border: 1px solid var(--border);
    border-radius: 0.5rem;
}
.ticket-merch-summary-title {
    margin: 0 0 0.6rem;
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--fg);
    display: flex;
    align-items: center;
    gap: 0.5rem;
}
.ticket-merch-summary-title i { color: var(--muted); }

/* Klikkbar variant for agent-portalen — header som hopper til Varer-
   fanen. Visuelt identisk med .ticket-merch-summary-title men full
   bredde + hover, så det er en tydelig affordance. */
.ticket-merch-summary-title-btn {
    appearance: none;
    background: none;
    border: none;
    margin: 0 0 0.6rem;
    padding: 0.2rem 0.4rem;
    width: 100%;
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--fg);
    display: flex;
    align-items: center;
    gap: 0.5rem;
    cursor: pointer;
    border-radius: 0.25rem;
    transition: background-color 0.12s;
    text-align: left;
}
.ticket-merch-summary-title-btn i { color: var(--muted); }
.ticket-merch-summary-title-btn:hover,
.ticket-merch-summary-title-btn:focus-visible {
    background-color: var(--shade-2);
}
.ticket-merch-summary-jump {
    margin-left: auto;
    font-weight: 400;
    font-size: 0.8rem;
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
}
.ticket-merch-summary-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}
/* Border-bottom på <li>en (ikke .ticket-merch-summary-row) — raden kan
   være enten <li> eller <a class="...-row"> inni <li>, og :last-child
   ville alltid matche den indre <a>en. Holdes på <li> for konsekvens. */
.ticket-merch-summary-list > li {
    border-bottom: 1px dashed var(--border);
}
.ticket-merch-summary-list > li:last-child {
    border-bottom: none;
}
.ticket-merch-summary-row {
    display: grid;
    grid-template-columns: auto 1fr auto auto;
    align-items: baseline;
    gap: 0.6rem;
    font-size: 0.9rem;
    padding: 0.35rem 0;
}
/* Klikkbar variant — peker til /store/product/{id} for varer som
   fortsatt finnes i butikken. Subtil hover så den signalerer "klikk
   for å se produktet" uten å skrike. */
a.ticket-merch-summary-row-link {
    color: inherit;
    text-decoration: none;
    border-radius: 0.25rem;
    margin: 0 -0.4rem;
    padding-left: 0.4rem;
    padding-right: 0.4rem;
    transition: background-color 0.12s;
}
a.ticket-merch-summary-row-link:hover,
a.ticket-merch-summary-row-link:focus-visible {
    background-color: var(--shade-2);
}
a.ticket-merch-summary-row-link:hover .ticket-merch-summary-name,
a.ticket-merch-summary-row-link:focus-visible .ticket-merch-summary-name {
    color: var(--accent);
}
.ticket-merch-summary-qty {
    font-weight: 600;
    color: var(--fg);
    white-space: nowrap;
}
.ticket-merch-summary-name {
    min-width: 0;
    color: var(--fg);
    word-wrap: break-word;
}
.ticket-merch-summary-name .badge {
    margin-left: 0.4rem;
    vertical-align: middle;
}
.ticket-merch-summary-price {
    color: var(--muted);
    font-size: 0.85rem;
    white-space: nowrap;
}
.ticket-merch-summary-sum {
    font-weight: 600;
    color: var(--fg);
    white-space: nowrap;
    min-width: 4.5rem;
    text-align: right;
}
.ticket-merch-summary-total {
    margin-top: 0.6rem;
    padding-top: 0.6rem;
    border-top: 1px solid var(--border);
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    font-size: 0.95rem;
}
.ticket-merch-summary-total strong { color: var(--fg); }

@media (max-width: 600px) {
    .ticket-merch-summary-row {
        grid-template-columns: auto 1fr;
        grid-template-areas:
            "qty name"
            ".   price"
            ".   sum";
        row-gap: 0.15rem;
    }
    .ticket-merch-summary-qty { grid-area: qty; }
    .ticket-merch-summary-name { grid-area: name; }
    .ticket-merch-summary-price { grid-area: price; text-align: left; }
    .ticket-merch-summary-sum { grid-area: sum; text-align: left; min-width: 0; }
}

/* ------ Back link ------ */
.back-link {
    display: inline-block;
    margin-bottom: 1rem;
    color: var(--muted);
    font-size: 0.9rem;
}
.back-link:hover { color: var(--accent); }

/* ------ Lightbox ------
   Full-screen image viewing. Used by components/lightbox.js on the
   product-detail page and reusable elsewhere. Keyboard bindings
   (Esc/←/→) are handled in the component — CSS is layout/look only. */
.lightbox-open { overflow: hidden; }  /* lock body scroll while open */

.lightbox {
    position: fixed;
    inset: 0;
    z-index: 1000;
    background: rgba(0, 0, 0, 0.88);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 2.5rem;
    opacity: 0;
    transition: opacity 0.18s ease-out;
}
.lightbox.open { opacity: 1; }

.lightbox-figure {
    margin: 0;
    max-width: 100%;
    max-height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.75rem;
}
.lightbox-image {
    max-width: 100%;
    max-height: calc(100vh - 8rem);
    object-fit: contain;
    cursor: pointer;             /* click on image → next */
    user-select: none;
    -webkit-user-drag: none;
}
/* Failed-load state: gives the lightbox a visible "bildet mangler"
   hint instead of a tiny browser broken-image icon. The alt-text
   set on the <img> by the JS error handler shows as the visible
   caption when the image itself can't render. */
.lightbox-image.lightbox-image-error {
    background: var(--shade-1);
    border: 1px dashed var(--border-strong);
    border-radius: var(--radius);
    min-width: 280px;
    min-height: 160px;
    padding: 2rem;
    color: var(--muted);
    font-style: italic;
}

/* ------ Form section (modern fieldset replacement) ------
   Card-style grouping of related fields with a small uppercase title.
   Replaces native <fieldset> + lifted <legend>, which read 90s. Use on
   any new admin/edit page that needs visual sub-grouping. */
.form-section {
    padding: 1.1rem 1.25rem 1.25rem;
    display: flex;
    flex-direction: column;
    gap: 1rem;
}
.form-section-title {
    margin: 0;
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--muted);
}
/* Tighter checkbox stack inside a form-section — pairs with
   .admin-checkbox-row.compact for category lists, permission grids, etc. */
.form-section-checks {
    display: flex;
    flex-direction: column;
    gap: 0;
}

/* Danger-zone — red-bordered .form-section variant for destructive
   actions, placed at the bottom of an edit page so users have to scroll
   past everything else first. GitHub's settings-page pattern. The
   destructive button sits aligned right; explanatory text on the left. */
.danger-zone {
    border-color: var(--icon-red);
    background: var(--icon-red-soft);
}
.danger-zone .form-section-title { color: var(--icon-red); }
.danger-zone-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
}
.danger-zone-text {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    flex: 1;
    min-width: 0;
}
.danger-zone-text strong { color: var(--fg); font-size: 0.95rem; }
.danger-zone-text .muted { font-size: 0.85rem; }

/* ------ File dropzone ------
   Drag-and-drop upload surface. Replaces bare <input type="file"> on
   modern admin pages — see components/file-dropzone.md.
   States: idle | hover (mouse over) | dragover (file dragged in) | busy. */
.dropzone {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.6rem;
    padding: 1.5rem 1rem;
    background: var(--shade-1);
    border: 2px dashed var(--border-strong);
    border-radius: var(--radius-lg);
    cursor: pointer;
    color: var(--muted);
    text-align: center;
    transition: border-color 0.12s, background 0.12s, color 0.12s;
}
.dropzone:hover {
    border-color: var(--accent);
    color: var(--accent);
}
.dropzone.is-dragover {
    border-color: var(--accent);
    background: var(--icon-blue-soft);
    color: var(--accent);
}
.dropzone.is-busy {
    cursor: wait;
    opacity: 0.7;
}
.dropzone-icon { font-size: 1.6rem; }
.dropzone-text { font-size: 0.9rem; font-weight: 500; color: var(--fg); }
.dropzone-hint { font-size: 0.78rem; color: var(--muted); }

/* Compact variant — thinner padding + single-row horizontal layout +
   smaller icon. For inline use under a comment form / textarea where
   the dropzone shouldn't dominate the surface visually. */
.dropzone.dropzone-compact {
    flex-direction: row;
    justify-content: flex-start;
    gap: 0.6rem;
    padding: 0.55rem 0.85rem;
    border-style: dashed;
    border-width: 1px;
    text-align: left;
}
.dropzone.dropzone-compact .dropzone-icon { font-size: 1rem; }
.dropzone.dropzone-compact .dropzone-text { font-size: 0.85rem; }
.dropzone.dropzone-compact .dropzone-hint {
    margin-left: auto;
    font-size: 0.75rem;
}
.dropzone input[type="file"] {
    /* Hide the native input — clicks on .dropzone trigger it via .click(). */
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}
.lightbox-counter {
    color: rgba(255, 255, 255, 0.85);
    font-size: 0.9rem;
    font-variant-numeric: tabular-nums;
}

.lightbox-close,
.lightbox-nav {
    position: fixed;
    background: rgba(255, 255, 255, 0.1);
    color: #fff;
    border: 0;
    border-radius: 50%;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background 0.12s;
}
.lightbox-close:hover,
.lightbox-nav:hover { background: rgba(255, 255, 255, 0.22); }
.lightbox-close:focus-visible,
.lightbox-nav:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }

.lightbox-close {
    top: 1rem;
    right: 1rem;
    width: 44px;
    height: 44px;
    font-size: 1.2rem;
}
.lightbox-nav {
    top: 50%;
    width: 52px;
    height: 52px;
    transform: translateY(-50%);
    font-size: 1.4rem;
}
.lightbox-prev { left: 1rem; }
.lightbox-next { right: 1rem; }

@media (max-width: 600px) {
    .lightbox { padding: 1rem; }
    .lightbox-nav { width: 44px; height: 44px; }
    .lightbox-prev { left: 0.5rem; }
    .lightbox-next { right: 0.5rem; }
}
