/* Agent shell layout — sidebar + topbar + main.
   Loaded only by agent.html. See docs/design.md §Agent layout. */

:root {
    --agent-sidebar-width: 220px;
    --agent-topbar-height: 64px;
    --ticket-sidebar-width: 320px;
    /* .agent-ticket-topbar visual height — 0.5rem padding top/bottom
       + 36px icon-btn + 1px border-bottom ≈ 53px. Rounded up to 56px
       for rounding-slack so we don't trigger side-scrollbar. Used by
       .agent-ticket-layout min-height so the sidebar border reaches
       the viewport bottom on short tickets, but without overflow. */
    --ticket-inline-topbar-height: 56px;
}

.agent-body {
    background: var(--shade-1);
    min-height: 100vh;
}

.agent-shell {
    min-height: 100vh;
    padding-left: var(--agent-sidebar-width);
    transition: padding-left 0.15s;
}
.agent-shell.sidebar-collapsed { padding-left: 0; }

/* ------ Sidebar (fixed, full viewport height) ------ */
.agent-sidebar {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    width: var(--agent-sidebar-width);
    background: var(--surface);
    border-right: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    padding: 0 0.75rem 1rem;
    z-index: 50;
    overflow-y: auto;
    transform: translateX(0);
    transition: transform 0.15s;
}
.agent-shell.sidebar-collapsed .agent-sidebar { transform: translateX(-100%); }

/* Drag-handle for sidebar width. Invisible hit-zone centered on the edge.
   Cursor-only hint (col-resize) — no visual line, matches the design
   guideline about non-shouty feedback.
   Hidden on mobile (the sidebar is a slide-in drawer there) and when collapsed. */
.agent-sidebar-resize {
    position: fixed;
    top: 0;
    bottom: 0;
    left: var(--agent-sidebar-width);
    width: 6px;
    margin-left: -3px;
    cursor: col-resize;
    z-index: 55;
    background: transparent;
    touch-action: none;
}
.agent-shell.sidebar-collapsed .agent-sidebar-resize { display: none; }

/* During drag: lock cursor on the entire page (otherwise it flickers when
   the mouse crosses elements with their own cursor style like inputs/buttons)
   + block text selection. Generic class — set by components/resizable.js
   regardless of which element is being dragged. */
body.is-resizing,
body.is-resizing * {
    cursor: col-resize !important;
    user-select: none !important;
}

.agent-nav-footer {
    margin-top: auto;
    padding-top: 1rem;
    border-top: 1px solid var(--border);
}
.agent-brand {
    height: var(--agent-topbar-height);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0 0.5rem;
}
/* Logo scales to fit the (drag-resizable) sidebar width. `max-width: 100%`
   shrinks the natural ~7:1 horizontal logo down on narrow sidebars; the
   `max-height: 26px` cap keeps it visually balanced (matches the original
   sidebar height and the user-portal topbar's 28px ballpark) when the
   sidebar is dragged wide. Light/dark variant swap is driven by the
   `.brand-logo.brand-logo-{light,dark}` rules in main.css. */
.agent-brand img {
    display: block;
    max-width: 100%;
    max-height: 26px;
    width: auto;
    height: auto;
}

.agent-nav { display: flex; flex-direction: column; gap: 0.15rem; margin-top: 0.5rem; }
/* Primary nav takes all remaining space so footer nav sits at the bottom */
.agent-sidebar > nav.agent-nav:first-of-type { flex: 1 1 auto; }
.agent-nav-item {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.65rem 0.85rem;
    color: var(--muted);
    border-radius: var(--radius);
    font-weight: 500;
    font-size: 0.95rem;
    position: relative;
    /* Containment for ellipsis on the text span — without overflow:hidden
       on the flex parent, white-space:nowrap on the child can still
       force the parent to grow. */
    overflow: hidden;
}
.agent-nav-item i {
    width: 1.2em;
    text-align: center;
    font-size: 1.05rem;
    color: var(--muted);
    flex-shrink: 0;  /* Icon keeps its natural size when sidebar narrows */
}
/* Text label truncates with ellipsis when the sidebar is too narrow.
   `min-width: 0` is the magic that lets a flex item shrink below its
   intrinsic content size. The badge selector below opts out so it
   keeps its full count visible. */
.agent-nav-item > span:not(.agent-nav-badge) {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.agent-nav-item:hover { background: var(--shade-1); color: var(--fg); }
.agent-nav-item:hover i { color: var(--accent); }
.agent-nav-item.active { background: var(--icon-blue-soft); color: var(--accent); }
.agent-nav-item.active i { color: var(--accent); }

.agent-nav-badge {
    margin-left: auto;
    min-width: 22px;
    height: 22px;
    padding: 0 6px;
    font-size: 0.75rem;
    font-weight: 700;
    color: var(--accent);
    background: var(--icon-blue-soft);
    border-radius: 999px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;  /* Badge keeps its size when text-label truncates */
}
.agent-nav-item.active .agent-nav-badge {
    background: var(--accent);
    color: #fff;
}

/* ------ Frame (topbar + main) ------ */
.agent-frame {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.agent-topbar {
    height: var(--agent-topbar-height);
    background: var(--surface);
    border-bottom: 1px solid var(--border);
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0 1.25rem;
}

.agent-burger {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    color: var(--muted);
    border: 0;
    font-size: 1.25rem;
    width: 40px;
    height: 40px;
    border-radius: var(--radius);
    cursor: pointer;
    flex-shrink: 0;
}
.agent-burger:hover { background: var(--shade-1); color: var(--fg); }


.agent-search {
    flex: 1;
    max-width: 600px;
    position: relative;
    display: block;
    margin: 0;
}
.agent-search-icon {
    position: absolute;
    top: 50%;
    left: 1rem;
    transform: translateY(-50%);
    color: var(--muted);
    pointer-events: none;
    display: flex;
    align-items: center;
}
.agent-search input {
    width: 100%;
    padding: 0.55rem 0.9rem 0.55rem 2.65rem;
    background: var(--shade-1);
    border: 1px solid transparent;
    border-radius: 999px;
    font-size: 0.95rem;
    font-family: inherit;
}
.agent-search input:focus { background: var(--surface); border-color: var(--border); outline: none; }

/* Mobile: search collapses to a clickable icon-button. Tap → expand the
   input across the rest of the topbar (trailing actions hide while
   expanded). Esc / outside-click / result-select collapses back.

   The breakpoint matches the rest of the topbar — when there isn't room
   for both a usable search field AND the action icons, we'd rather show
   the action icons by default and reveal search on demand. */
@media (max-width: 720px) {
    .agent-search {
        flex: none;
        max-width: none;
        width: 38px;
    }
    .agent-search:not(.is-expanded) {
        background: var(--shade-1);
        border-radius: 50%;
        height: 38px;
        cursor: pointer;
    }
    .agent-search:not(.is-expanded) .agent-search-icon {
        position: static;
        transform: none;
        width: 100%;
        height: 100%;
        justify-content: center;
        pointer-events: none;
    }
    .agent-search:not(.is-expanded) input { display: none; }
    .agent-search:not(.is-expanded) .agent-search-results { display: none !important; }
    /* Expanded: take all remaining horizontal space and hide only the
       SECONDARY actions (create + apps + theme) — notifications + user-menu
       stay reachable so an agent can check alerts or log out without
       having to close search first. */
    .agent-search.is-expanded {
        flex: 1;
        width: auto;
    }
    .agent-search.is-expanded ~ .agent-topbar-actions #agent-create-menu,
    .agent-search.is-expanded ~ .agent-topbar-actions #agent-apps-menu,
    .agent-search.is-expanded ~ .agent-topbar-actions #agent-theme-toggle { display: none; }
    /* Search-results dropdown — clamp to viewport so it doesn't overflow
       the right edge on narrow phones. */
    .agent-search-results {
        max-width: calc(100vw - 1rem);
    }
}

/* Narrow phones (≤ 480px): topbar is too dense even when search is
 * collapsed. Hide apps-menu and theme-toggle by default — apps is
 * rarely used in the field, theme is reachable via the user-menu
 * dropdown (mirrors the user-portal pattern). Keeps: burger,
 * search-icon, create, notifications, user-menu. */
@media (max-width: 480px) {
    #agent-apps-menu,
    #agent-theme-toggle { display: none; }
}

/* Global-search dropdown — lives under the topbar search input. */
.agent-search-results {
    /* Reuse .dropdown-menu styling but make it wider + anchored under the input. */
    position: absolute;
    top: calc(100% + 6px);
    left: 0;
    right: auto;
    width: 100%;
    max-width: 600px;
    max-height: 480px;
    overflow-y: auto;
    padding: 0.25rem;
    z-index: 120;
}
/* Status messages inside the dropdown ("Search failed", "No matches").
   Match search-row padding so the empty/error state aligns visually. */
.agent-search-results > .muted { padding: 0.5rem 0.75rem; margin: 0; }
.agent-search-results .search-section { padding: 0.25rem 0; }
.agent-search-results .search-section h4 {
    margin: 0;
    padding: 0.35rem 0.65rem;
    font-size: 0.7rem;
    font-weight: 600;
    color: var(--muted);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}
.search-row {
    display: flex;
    align-items: center;
    gap: 0.65rem;
    padding: 0.5rem 0.65rem;
    border-radius: var(--radius);
    color: var(--fg);
    text-decoration: none;
    font-size: 0.9rem;
    cursor: pointer;
}
.search-row:hover,
.search-row.is-active {
    background: var(--shade-1);
    color: var(--fg);
}
.search-row-main {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
}
.search-row-main > * {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.search-row-title { color: var(--fg); }
.search-row-sub { font-size: 0.78rem; }
.search-row-meta {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.78rem;
}

.agent-topbar-actions { display: flex; align-items: center; gap: 0.25rem; margin-left: auto; }

/* Main content area.
   Cap the reading width on ultrawide displays so lists and ticket
   detail don't stretch across the full screen. Centred via auto
   margins; the topbar stays full-width (it lives outside this rule). */
.agent-frame > main#app {
    max-width: 1400px;
    width: 100%;
    margin: 0 auto;
    padding: 1.5rem 1.75rem;
    flex: 1;
}

/* ------ Mobile ------ */
@media (max-width: 900px) {
    .agent-shell { padding-left: 0; }
    .agent-sidebar {
        z-index: 100;
        transform: translateX(-100%);
        box-shadow: var(--shadow);
    }
    .agent-sidebar.open { transform: translateX(0); }
    /* Mobile = slide-in drawer, not resizable. */
    .agent-sidebar-resize { display: none; }
    /* Collapse class is desktop-only; ignore it on mobile. */
    .agent-shell.sidebar-collapsed .agent-sidebar { transform: translateX(-100%); }
    .agent-shell.sidebar-collapsed .agent-sidebar.open { transform: translateX(0); }
}

/* ------ Agent dashboard ------ */
.agent-dashboard h1 { font-weight: 400; font-size: 2rem; margin-bottom: 1.5rem; color: var(--fg); }

/* ------ New ticket — drawer form + success state + confetti ------
   Used by views/agent-new-ticket-drawer.js. Surface is inherited from
   .drawer-panel; here: only form structure + success screen. */
.new-ticket-form { padding: 0; }
.new-ticket-form .admin-form-field { margin-bottom: 1rem; }
.new-ticket-form .admin-form-actions {
    display: flex;
    gap: 0.5rem;
    justify-content: flex-end;
    margin-top: 1.25rem;
}
.new-ticket-draft-banner {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.5rem 0.75rem;
    background: var(--icon-amber-soft);
    color: var(--fg);
    border-radius: var(--radius);
    font-size: 0.85rem;
    margin-bottom: 1rem;
}
.new-ticket-draft-banner i { color: var(--icon-amber); }
.new-ticket-draft-banner button { margin-left: auto; }
/* Asset-link banner — shown at top of the new-ticket form when opened
   from a CMDB asset page. Blue-soft variant (vs amber for draft) so the
   two banners don't look identical when both are present. */
.new-ticket-link-asset {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.5rem 0.75rem;
    background: var(--icon-blue-soft);
    color: var(--icon-blue);
    border-radius: var(--radius);
    font-size: 0.85rem;
    margin-bottom: 1rem;
}
.new-ticket-link-asset i { color: var(--icon-blue); }
.new-ticket-link-asset strong { color: var(--fg); }
.new-ticket-selected-user {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.5rem 0.75rem;
    background: var(--icon-blue-soft);
    color: var(--fg);
    border-radius: var(--radius);
    font-size: 0.9rem;
}
.new-ticket-selected-user i { color: var(--accent); margin-right: 0.4rem; }
.new-ticket-editor {
    /* CommentEditor produces its own outline; it just needs a min-height
       so the agent sees it as a "write here" field. */
    min-height: 180px;
}

/* ------ Announcement-drawer specific ------ */
.type-pills {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
}
.type-pill {
    flex: 1 1 120px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    padding: 0.55rem 0.75rem;
    background: var(--surface);
    color: var(--fg);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
    cursor: pointer;
    font-size: 0.9rem;
    transition: background 0.1s, border-color 0.1s, color 0.1s;
}
.type-pill:hover { border-color: var(--accent); }
.type-pill.is-active {
    border-color: transparent;
    font-weight: 600;
}
.type-pill.is-active.type-pill-blue  { background: var(--icon-blue-soft);  color: var(--icon-blue);  }
.type-pill.is-active.type-pill-amber { background: var(--icon-amber-soft); color: var(--icon-amber); }
.type-pill.is-active.type-pill-red   { background: var(--icon-red-soft);   color: var(--icon-red);   }

/* Split action-row: nav buttons left, form-actions right. */
.admin-form-actions.admin-form-actions-split {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    flex-wrap: wrap;
}
.admin-form-actions-left,
.admin-form-actions-right {
    display: flex;
    gap: 0.4rem;
    flex-wrap: wrap;
}

/* `.link-button` and `.link-button-hint` moved to main.css — general
   button-system primitives shared across both shells (user-portal +
   agent). See `docs/components/button.md`. */

/* Active announcements block in drawer — divider style (not box)
   after user feedback. Placed AFTER the publish button so that
   it's clear they are NOT part of the "Publish" action. */
.active-meldinger-block {
    margin-top: 2rem;
    padding-top: 1.25rem;
    border-top: 1px solid var(--border);
}
.active-meldinger-title {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    margin: 0 0 0.3rem;
    font-size: 0.9rem;
    font-weight: 600;
    color: var(--fg);
}
.active-meldinger-count { font-weight: 400; color: var(--muted); }
.active-meldinger-help { margin: 0 0 0.75rem; font-size: 0.78rem; }
.active-meldinger-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
}
.active-meldinger-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.45rem 0.6rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    font-size: 0.85rem;
}
.active-meldinger-title-text {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}

/* Templates modal — list of archived items with "Use as template" / "Open". */
.templates-list {
    list-style: none;
    margin: 0.75rem 0 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    max-height: 480px;
    overflow-y: auto;
}
.templates-row {
    display: grid;
    grid-template-columns: auto 1fr auto;
    align-items: center;
    gap: 0.75rem;
    padding: 0.6rem 0.85rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
}
.templates-row-body {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    min-width: 0;
}
.templates-row-body strong {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.templates-row-period { font-size: 0.78rem; }
.templates-row-actions {
    display: flex;
    gap: 0.3rem;
    flex-shrink: 0;
}
@media (max-width: 480px) {
    .templates-row { grid-template-columns: 1fr; }
    .templates-row-actions { justify-content: flex-end; }
}

.date-range-presets {
    display: flex;
    gap: 0.4rem;
    flex-wrap: wrap;
    margin-bottom: 0.6rem;
}
.date-range-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.6rem;
}
.date-range-grid label {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
}
@media (max-width: 480px) {
    .date-range-grid { grid-template-columns: 1fr; }
}

/* Success state — full drawer-body, centered, green accent. */
.new-ticket-success {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    padding: 2rem 1rem;
    position: relative;
}
.new-ticket-success-icon {
    width: 72px;
    height: 72px;
    border-radius: 50%;
    background: var(--icon-green-soft);
    color: var(--icon-green);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 2.4rem;
    margin-bottom: 1rem;
    animation: ticket-success-pop 0.45s cubic-bezier(0.16, 1.2, 0.4, 1) both;
}
@keyframes ticket-success-pop {
    0%   { transform: scale(0); opacity: 0; }
    100% { transform: scale(1); opacity: 1; }
}
.new-ticket-success-title {
    font-size: 1.4rem;
    font-weight: 600;
    color: var(--fg);
    margin: 0 0 0.4rem;
}
.new-ticket-success-sub {
    margin: 0 0 1.5rem;
    max-width: 28ch;
}
.new-ticket-success-actions {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    width: 100%;
    max-width: 280px;
}
.new-ticket-success-actions .btn { justify-content: center; }

/* Confetti CSS moved to main.css so it's available in both
   shells (agent + user-portal). Use via helpers/confetti.js. */

.agent-stats {
    display: grid;
    /* 4 equally sized tiles. Breaks to 2x2 on narrow screens. */
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 1rem;
    margin-bottom: 1.5rem;
}
@media (max-width: 720px) {
    .agent-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.agent-stat {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 0.15rem;
    min-height: 110px;
    padding: 1rem 1.1rem;
    border-radius: 12px;
    color: #fff;
    text-decoration: none;
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.06);
    transition: transform 0.15s, box-shadow 0.15s;
}
.agent-stat:hover {
    transform: translateY(-2px);
    box-shadow: 0 8px 22px rgba(0, 0, 0, 0.1);
    color: #fff;
}
.agent-stat-number { font-size: 2rem; font-weight: 600; line-height: 1; }
.agent-stat-label { font-size: 0.95rem; font-weight: 600; margin-top: 0.4rem; }
.agent-stat-sub { font-size: 0.78rem; opacity: 0.85; }

/* Legacy domain-specific stat-tile variants removed 2026-05-14. Both
   agent-dashboard and CMDB dashboard now use .stat-token + token-aligned
   variants (.stat-blue / .stat-amber / .stat-green / .stat-red /
   .stat-purple) further down in this file. Those follow design.md
   §Palette (gradient endpoints come from --stat-*-from / --stat-*-to
   tokens in main.css) so the colours can be changed in one place. */

/* ------ Dashboard layout (2026-04-25 — match old app) ------
   Main content on the left (stat-tiles + charts), sticky sidebar right,
   "My tickets" full-width at the bottom. Mobile: everything stacks. */
.agent-dashboard-main {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1.5rem;
    margin-bottom: 1.5rem;
}
@media (min-width: 1100px) {
    .agent-dashboard-main { grid-template-columns: minmax(0, 1fr) 320px; }
}
.agent-dashboard-col { display: flex; flex-direction: column; gap: 1.25rem; min-width: 0; }
.agent-dashboard-sidebar { display: flex; flex-direction: column; gap: 1.25rem; min-width: 0; }

/* Remove default <section>/<h2>-margin so the sidebar heading ("My
   tickets") sits on the same baseline as the top of the stat-tile row
   in the left column. */
.agent-dashboard-section { margin: 0; }
.agent-dashboard-section > h2 {
    margin: 0 0 0.85rem;
    font-size: 1.05rem;
    font-weight: 600;
    color: var(--fg);
}

/* Kept for backwards compatibility — older views/code-paths still
   reference this class. .agent-dashboard-main is the new standard. */
.agent-dashboard-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1.5rem;
}
@media (min-width: 1100px) {
    .agent-dashboard-grid { grid-template-columns: 1fr 320px; }
}

/* Charts row — gauge | line | donut. Stacks on mobile, 3 columns on desktop. */
.agent-dashboard-charts {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1rem;
}
@media (min-width: 720px) {
    .agent-dashboard-charts { grid-template-columns: repeat(3, 1fr); }
}
.agent-dashboard-charts .chart-card {
    padding: 1rem 1.1rem;
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    /* Explicit height — the Chart.js doughnut otherwise grows unbounded
       and squeezes out of the card. Width:100% + maintainAspectRatio:false
       means the canvas adapts to the parent's height — we set it here. */
    height: 240px;
}
.agent-dashboard-charts .chart-card h3 {
    margin: 0;
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--fg);
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.5rem;
    flex-shrink: 0;
}
.agent-dashboard-charts .chart-card h3 .muted {
    font-size: 0.78rem;
    font-weight: 400;
}
.agent-dashboard-charts .chart-canvas-wrap {
    flex: 1;
    min-height: 0;
    position: relative;
    overflow: hidden;
}
.agent-dashboard-charts .chart-canvas-wrap > canvas {
    max-width: 100%;
    max-height: 100%;
}

/* Gauge — semi-circle doughnut via Chart.js. Matches the old app. */
.chart-gauge {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    justify-content: flex-end;
    gap: 0.4rem;
    min-height: 0;
}
.gauge-canvas-wrap {
    position: relative;
    flex: 1;
    min-height: 0;
    width: 100%;
}
.gauge-canvas-wrap > canvas {
    max-width: 100%;
    max-height: 100%;
}
.gauge-value {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0.25rem;
    text-align: center;
    font-size: 1.4rem;
    font-weight: 600;
    color: var(--fg);
    line-height: 1;
    pointer-events: none;
}
.gauge-value .gauge-unit { font-size: 0.85rem; color: var(--muted); margin-left: 2px; }
.gauge-note { text-align: center; font-size: 0.78rem; margin: 0; }

.agent-dashboard-charts-link { margin-top: 0.5rem; font-size: 0.9rem; }
.agent-dashboard-charts-link a {
    color: var(--accent);
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
}
.agent-dashboard-charts-link a:hover { text-decoration: underline; }

.agent-dashboard-mine { margin-top: 1.5rem; }
.agent-dashboard-mine h2 {
    font-size: 1.25rem;
    font-weight: 500;
    margin: 0 0 0.85rem;
    color: var(--fg);
}

/* Dashboard activity feed — right column on desktop. Compact row with
   actor avatar + verb + clickable ticket id + relative time. Data
   source: /api/hd/agent/activity (helpdesk-domain events, dept-scoped). */
/* Container is a card (surface-tokens inherited from CANONICAL ROW-SURFACE
   in main.css). Rows inside are separated by subtle bottom-borders — not
   per-row shadow like .list-item would have given, because a feed view should
   be calm, not a "click-me" affordance per row. */
.activity-feed {
    list-style: none;
    margin: 0;
    padding: 0.25rem 0;
    display: flex;
    flex-direction: column;
    /* Surface inherited from :is() in main.css. */
}
.activity-feed-row {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 0.1rem;
    padding: 0.65rem 0.85rem;
    font-size: 0.82rem;
    line-height: 1.3;
    border-bottom: 1px solid var(--border);
}
.activity-feed-row:last-child { border-bottom: 0; }
.activity-feed-row:hover { background: var(--shade-1); }
/* Line is plain inline flow (NOT flex) so verb + ticket-link wrap word-
   by-word like normal text — just like the old app. The actor (avatar +
   name) is still its own inline-flex unit to keep the avatar centered. */
.activity-feed-line {
    line-height: 1.5;
    word-spacing: 0.15rem;
}
.activity-feed-row .user-link,
.activity-feed-row .activity-actor {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    vertical-align: middle;
    cursor: pointer;
    color: var(--fg);
    margin-right: 0.15rem;
}
.activity-feed-row .user-link:hover { color: var(--accent); }
.activity-feed-row .avatar.avatar-xs {
    width: 22px;
    height: 22px;
    font-size: 0.65rem;
}
.activity-feed-action { color: var(--muted); }
.activity-feed-line a {
    color: var(--accent);
    text-decoration: none;
    font-variant-numeric: tabular-nums;
    /* No nowrap/ellipsis: long titles should wrap word-by-word inline
       with the verb, like the old app — not pushed onto a forced line. */
    overflow-wrap: anywhere;
    min-width: 0;
}
.activity-feed-line a:hover { text-decoration: underline; }
/* Inline relative-time at the end of the sentence — "X ago". */
.activity-feed-time {
    color: var(--muted);
    white-space: nowrap;
}

/* ------ Agent ticket detail page ------
   Flat layout, no per-section cards. Matches old shuffle-card layout
   where metadata lives in a thin sidebar list, comments flow with
   dashed separators, and the top is a single toolbar row. */

/* Toolbar strip sitting directly below the app topbar.
   Full-bleed against the main content padding (negative margin
   cancels the 1.75rem horizontal padding on #app), subtle tinted
   background to separate it visually from the comment thread. */
.agent-ticket-topbar {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin: -1.5rem -1.75rem 0;
    padding: 0.5rem 1.25rem;
    background: var(--shade-1);
    border-bottom: 1px solid var(--border);
}
.agent-ticket-back {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    color: var(--muted);
    border-radius: 50%;
}
.agent-ticket-back:hover { background: var(--shade-1); color: var(--fg); }
.agent-ticket-title {
    margin: 0;
    font-size: 1.25rem;
    font-weight: 600;
    flex: 1;
}
.agent-ticket-actions { display: flex; gap: 0.4rem; }

/* ----- Generic page toolbar -----
   `.page-toolbar` is the generalised version of `.agent-ticket-topbar`. Used
   at the top of agent views that need a title + horizontal action row
   (back-link, page actions, counter). Same visual treatment as the ticket-
   detail topbar: tinted background strip, border-bottom, negative margin
   to full-bleed against the parent's padding (the parent is either `#app`
   or `.detail-main` — both have `1.5rem 1.75rem` padding, so the same
   negative margins work). Migration: `.agent-ticket-topbar` should move to
   `.page-toolbar` in a follow-up — kept separate now because `.agent-
   ticket-title` is also used for ticket-list-row titles in
   `agent-tickets.js`, and a global rename would cross contexts. */
.page-toolbar {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin: -1.5rem -1.75rem 1.25rem;
    padding: 0.5rem 1.25rem;
    background: var(--shade-1);
    border-bottom: 1px solid var(--border);
}
.page-toolbar-title {
    margin: 0;
    font-size: 1.1rem;
    font-weight: 600;
    color: var(--fg);
    /* Doesn't claim flex:1 — the actions/counter live in their own group
       to the right via margin-left:auto, so the title sits at the natural
       left next to the sidebar-toggle. */
}
.page-toolbar-actions {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    margin-left: auto;
    /* Below ~720px the action row would wrap awkwardly into the title.
       Hide secondary actions on narrow viewports; primary actions (counter,
       sidebar toggle) keep working since they sit outside this row. */
}
.page-toolbar-counter {
    font-size: 0.85rem;
    color: var(--muted);
    padding: 0 0.5rem 0 0.6rem;
    white-space: nowrap;
}
/* `.page-toolbar-action` is the link-button used for placeholder actions
   today and for real ones later. Looks like a text-link with optional
   leading icon — sits between the title and the counter. Disabled state
   uses opacity + not-allowed cursor so it's clear the action exists but
   isn't wired up yet (Phase 2 follow-up). */
.page-toolbar-action {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.35rem 0.65rem;
    background: transparent;
    border: 0;
    border-radius: var(--radius);
    color: var(--accent);
    font: inherit;
    font-size: 0.88rem;
    cursor: pointer;
    transition: background 0.12s, color 0.12s;
}
.page-toolbar-action:hover:not(:disabled) {
    background: var(--icon-blue-soft);
}
.page-toolbar-action:disabled {
    opacity: 0.55;
    cursor: not-allowed;
}
.page-toolbar-action i { color: inherit; }

/* Sidebar-toggle button — leftmost element when present. Uses .icon-btn
   styling (circle outline) but communicates state via aria-pressed. When
   the sidebar is hidden the toggle inverts (accent fill) to signal "click
   again to bring it back". */
.page-toolbar-sidebar-toggle[aria-pressed="false"] {
    border-color: var(--accent);
    color: var(--accent);
    background: var(--icon-blue-soft);
}

/* Presence — avatars of other agents currently viewing the ticket.
   Sits between title and toolbar actions; overlap-stacked. */
.agent-presence { display: flex; margin-right: 0.5rem; }
.agent-presence:empty { display: none; }
.agent-presence .presence-avatar {
    width: 28px;
    height: 28px;
    font-size: 0.7rem;
    margin-left: -6px;
    border: 2px solid var(--shade-1);
    background: var(--accent);
    color: #fff;
}
.agent-presence .presence-avatar:first-child { margin-left: 0; }
/* Circle outline icon button — used for the top-right actions row. */
.icon-btn {
    width: 36px;
    height: 36px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: 1px solid var(--border);
    border-radius: 50%;
    color: var(--muted);
    cursor: pointer;
    transition: border-color 0.12s, color 0.12s, background 0.12s;
}
.icon-btn:hover { border-color: var(--accent); color: var(--accent); background: var(--icon-blue-soft); }
/* Active state for toggle buttons — accent-colored border + background so
   the user sees that the toggle is ON. Used by "Show system messages" in
   the ticket topbar (default off → click → on). The sidebar toggle also has
   aria-pressed, but there the layout change itself is the primary
   feedback, so we don't visualize the button on top. */
.icon-btn[data-toggle][aria-pressed="true"] {
    border-color: var(--accent);
    color: var(--accent);
    background: var(--icon-blue-soft);
}

.agent-tabs {
    display: flex;
    gap: 0.25rem;
    border-bottom: 1px solid var(--border);
    margin: 0 0 1.25rem;
}
.agent-tab {
    background: transparent;
    border: 0;
    border-bottom: 2px solid transparent;
    padding: 0.7rem 1.1rem;
    font-size: 0.95rem;
    font-weight: 500;
    color: var(--muted);
    cursor: pointer;
    border-radius: 0;
}
.agent-tab:hover:not(:disabled) { color: var(--fg); }
.agent-tab.active {
    color: var(--accent);
    border-bottom-color: var(--accent);
}
.agent-tab:disabled { color: var(--border); cursor: not-allowed; }

/* Two-column layout: main (comments) | sidebar (metadata).
   Sidebar width is a CSS variable so drag-resize can adjust it.
   Gap: 0 — a 1px border on the sidebar provides visual separation + drag indicator.
   Stretch align-items so the sidebar border spans the full layout height
   (not just the sidebar content), so it looks like a persistent panel. */
.agent-ticket-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) var(--ticket-sidebar-width);
    gap: 0;
    align-items: stretch;
    position: relative;
    /* Negative top-margin cancels the #app padding so the sidebar starts
       all the way up against the topbar — matches the old design. */
    margin-top: 0;
    /* Fill the viewport below the topbars so the sidebar border stretches
       to the bottom on short tickets too — without triggering a scrollbar
       when content actually fits (min-height, not height). Shorter
       than main#app-bottom-padding (1.5rem) to avoid overflow. */
    min-height: calc(
        100vh
        - var(--agent-topbar-height)
        - var(--ticket-inline-topbar-height)
        - 1.5rem
    );
}
@media (max-width: 900px) {
    .agent-ticket-layout { grid-template-columns: 1fr; }
}
.agent-ticket-main {
    min-width: 0;
    padding: 1.25rem 1.75rem 4rem 0;
}
.agent-ticket-sidebar {
    min-width: 0;
    border-left: 1px solid var(--border);
    padding: 1.25rem 0 1.25rem 1.75rem;
}
/* Mobile: sidebar becomes a right-slide-in drawer instead of stacking
 * below main content. Default state on mobile = drawer closed (off-screen
 * right). Toggle button (or backdrop tap) opens / closes. The class
 * .sidebar-hidden carries the closed state — same flag desktop uses for
 * "panel removed from grid" — but on mobile it means "drawer slid out".
 *
 * Initial render forces .sidebar-hidden on mobile regardless of stored
 * desktop preference (handled in JS), so the drawer doesn't pop open on
 * page load. */
@media (max-width: 900px) {
    .agent-ticket-main { padding-right: 0; }
    .agent-ticket-sidebar {
        position: fixed;
        top: var(--agent-topbar-height, 64px);
        right: 0;
        bottom: 0;
        width: min(360px, 90vw);
        background: var(--surface);
        border-left: 1px solid var(--border);
        box-shadow: -8px 0 24px rgba(0, 0, 0, 0.15);
        padding: 1.25rem;
        z-index: 60;
        overflow-y: auto;
        transform: translateX(0);
        transition: transform 0.2s;
    }
    /* Override the desktop rule that does display:none on .sidebar-hidden:
     * on mobile we keep the element rendered so it can transition. */
    .agent-ticket-layout.sidebar-hidden .agent-ticket-sidebar {
        display: block;
        transform: translateX(100%);
        box-shadow: none;
    }
    /* Layout always 1-col on mobile, regardless of sidebar-hidden state. */
    .agent-ticket-layout,
    .agent-ticket-layout.sidebar-hidden { grid-template-columns: 1fr; }
    /* Resize handle is desktop-only; the mobile drawer is fixed-width. */
    .agent-ticket-sidebar-resize { display: none !important; }
    /* Backdrop overlay — visible whenever the drawer is open (= sidebar
     * is NOT hidden). Tap to close (handler in agent-ticket-detail.js). */
    .agent-ticket-sidebar-backdrop {
        position: fixed;
        inset: 0;
        background: rgba(0, 0, 0, 0.4);
        z-index: 55;
        transition: opacity 0.2s;
        cursor: pointer;
    }
    .agent-ticket-layout.sidebar-hidden .agent-ticket-sidebar-backdrop {
        opacity: 0;
        pointer-events: none;
    }
}
/* Backdrop is mobile-only — hide on desktop entirely. */
.agent-ticket-sidebar-backdrop { display: none; }
@media (max-width: 900px) {
    .agent-ticket-sidebar-backdrop { display: block; }
}

/* Toggled-off state — sidebar hidden, main takes full width. Used by
   the toggle button in the topbar + by stored localStorage preference. */
.agent-ticket-layout.sidebar-hidden {
    grid-template-columns: 1fr;
}
.agent-ticket-layout.sidebar-hidden .agent-ticket-sidebar,
.agent-ticket-layout.sidebar-hidden .agent-ticket-sidebar-resize {
    display: none;
}
.agent-ticket-layout.sidebar-hidden .agent-ticket-main { padding-right: 0; }

/* Drag-handle for the ticket sidebar. Centered on the sidebar border (6px
   hit-zone around the 1px line). Invisible; cursor col-resize + the visible
   border are the visual cues. */
.agent-ticket-sidebar-resize {
    position: absolute;
    top: 0;
    bottom: 0;
    right: calc(var(--ticket-sidebar-width) - 3px);
    width: 6px;
    cursor: col-resize;
    z-index: 5;
    background: transparent;
    touch-action: none;
}
@media (max-width: 900px) {
    .agent-ticket-sidebar-resize { display: none; }
}

/* ------ Sidebar sections (no cards, flat) ------ */
.agent-sidebar-section { margin-bottom: 1.5rem; }
.agent-sidebar-heading {
    margin: 0 0 0.75rem;
    font-size: 1rem;
    font-weight: 600;
    color: var(--muted);
}

/* Announcement detail-drawer (/agent/settings/announcements). Hosts
   metadata, the rendered content, the Updates thread + post-form
   and the action row. Designed to live inside .drawer-body so it
   doesn't repaint a surface — sits on the drawer's own background. */
.ann-detail-meta { margin-bottom: 1rem; display: flex; flex-direction: column; gap: 0.6rem; }
.ann-detail-times { display: grid; grid-template-columns: 80px 1fr; gap: 0.25rem 0.75rem; margin: 0; font-size: 0.85rem; }
.ann-detail-times dt { color: var(--muted); font-weight: 500; }
.ann-detail-times dd { margin: 0; }
.ann-detail-content {
    background: var(--shade-1);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 0.75rem 1rem;
    margin-bottom: 1.25rem;
}
.ann-detail-thread { margin-bottom: 1.25rem; }
.ann-thread-list { display: flex; flex-direction: column; gap: 0.75rem; margin: 0.5rem 0 1rem; }
.ann-thread-item {
    display: flex;
    gap: 0.75rem;
    padding: 0.75rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
}
.ann-thread-item .avatar { width: 36px; height: 36px; flex-shrink: 0; }
.ann-thread-body { flex: 1; min-width: 0; }
.ann-thread-head { display: flex; align-items: baseline; gap: 0.5rem; margin-bottom: 0.3rem; }
.ann-thread-head strong { font-size: 0.9rem; color: var(--fg); }
.ann-thread-head time { font-size: 0.78rem; color: var(--muted); }
.ann-thread-empty { font-style: italic; }
.ann-thread-form 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-family: inherit;
    font-size: 0.9rem;
    resize: vertical;
    min-height: 4em;
}
.ann-detail-actions { border-top: 1px solid var(--border); padding-top: 1rem; }
.ann-action-row { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0.5rem 0 0; }
.ann-action-row .ann-danger { color: var(--icon-red); border-color: var(--icon-red-soft); }
.ann-action-row .ann-danger:hover { background: var(--icon-red-soft); color: var(--icon-red); border-color: var(--icon-red); }
.ann-action-hint { margin: 0.6rem 0 0; font-size: 0.82rem; }

/* Announcement sidebar-card on ticket-detail. Lifts the linkage out
   visually so an agent scanning the sidebar immediately sees that the
   ticket is part of a larger incident. Soft accent-tinted background
   to read as a notice without screaming. */
.ticket-announcement-card {
    background: var(--icon-amber-soft);
    border: 1px solid var(--icon-amber);
    border-radius: var(--radius);
    padding: 0.75rem;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}
.ticket-announcement-head {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
}
.ticket-announcement-icon {
    color: var(--icon-amber);
    font-size: 1rem;
    line-height: 1.4;
    flex-shrink: 0;
}
.ticket-announcement-title {
    font-weight: 600;
    color: var(--fg);
    line-height: 1.3;
}
.ticket-announcement-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
}
.ticket-announcement-unlink {
    align-self: flex-start;
}

/* Ticket-sidebar CMDB-asset card — surfaces hd_tickets.source='cmdb' +
   source_id by looking up cmdb_assets. Distinct from the legacy M2M
   field below in Saksdetaljer. Hover-lift inherited from .surface
   pattern is reproduced manually here since the card is a plain <a>. */
.ticket-cmdb-asset {
    display: grid;
    grid-template-columns: auto 1fr auto;
    align-items: center;
    gap: 0.6rem;
    padding: 0.6rem 0.7rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    color: var(--fg);
    text-decoration: none;
    transition: transform .08s ease, box-shadow .12s ease;
}
.ticket-cmdb-asset:hover {
    transform: translateY(-1px);
    box-shadow: var(--shadow-sm, 0 1px 3px rgba(0,0,0,.08));
    border-color: var(--icon-blue);
}
.ticket-cmdb-asset-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border-radius: 50%;
    background: var(--icon-blue-soft);
    color: var(--icon-blue);
    flex-shrink: 0;
}
.ticket-cmdb-asset-body {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    min-width: 0;
    font-size: 0.85rem;
}
.ticket-cmdb-asset-body > * {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.ticket-cmdb-asset-name { font-weight: 600; }
.ticket-cmdb-asset-eol {
    color: var(--icon-red);
    font-size: 0.78rem;
    font-weight: 500;
    margin-left: 0.25rem;
}
.ticket-cmdb-asset-chevron { color: var(--muted); flex-shrink: 0; }

.ticket-cmdb-asset-pending {
    margin: 0;
    padding: 0.55rem 0.7rem;
    background: var(--surface-2, var(--shade-1));
    border-radius: var(--radius);
    font-size: 0.85rem;
}

/* ----- CMDB asset drawer ----- */
/* Specific structure for the asset-drawer head — icon-tile + name +
   brand/model. Distinct content from `.user-profile-head` (avatar +
   customer-line). Reusable parts are extracted into generic classes
   below (`.drawer-facts`, `.drawer-ticket-list`). Owner row uses the
   shared `.user-card` (main.css + docs/components/user-card.md). */
.cmdb-drawer-head {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 0.7rem;
    align-items: center;
    margin-bottom: 0.9rem;
}
.cmdb-drawer-head-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 48px;
    height: 48px;
    border-radius: 12px;
    background: var(--icon-blue-soft);
    color: var(--icon-blue);
    font-size: 1.3rem;
    flex-shrink: 0;
}
.cmdb-drawer-head-text {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    min-width: 0;
}
.cmdb-drawer-name { font-size: 1.05rem; color: var(--fg); }
.cmdb-drawer-badges {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
    margin-bottom: 0.9rem;
}

/* ----- Drawer-facts (generic) ----- */
/* dt/dd field list, single-column dashed-divider rows. Reusable from
   any drawer view that needs a compact "key: value" panel — e.g.
   cmdb-asset-drawer, future ticket-quickview enrichments. Distinct
   from `.user-profile-facts` which is 2-col for short user fields. */
.drawer-facts {
    margin: 0;
    display: flex;
    flex-direction: column;
}
.drawer-facts > div {
    display: grid;
    grid-template-columns: 110px 1fr;
    gap: 0.6rem;
    align-items: baseline;
    font-size: 0.85rem;
    padding: 0.35rem 0;
    border-bottom: 1px dashed var(--border);
}
.drawer-facts > div:last-child { border-bottom: 0; }
.drawer-facts dt { color: var(--muted); font-weight: 500; }
.drawer-facts dd { margin: 0; color: var(--fg); overflow-wrap: anywhere; }

/* ----- Drawer-ticket-list (generic) ----- */
/* Compact ticket-row list rendered inside a drawer body. Hover-shade
   instead of full surface-lift since the drawer body itself is
   already a contained context. */
.drawer-ticket-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
}
.drawer-ticket-list a {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    padding: 0.45rem 0.6rem;
    text-decoration: none;
    color: var(--fg);
    border-radius: var(--radius);
    font-size: 0.85rem;
}
.drawer-ticket-list a:hover { background: var(--shade-1); }
.drawer-ticket-list-title {
    font-weight: 500;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Drawer section spacing — light heading + content gap. Used by any
   drawer view that needs labelled sections (Eier, Historikk, …).
   `<details>`-based collapsible variants live in `.user-profile-section`. */
.drawer-section { margin-top: 1rem; }
.drawer-section-head {
    margin: 0 0 0.5rem;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--fg);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.5rem;
}

/* Pick-list inside the "Knytt til driftsmelding" modal. Each row is a
   full-width button so the entire surface is the click target. */
.ticket-announcement-list {
    list-style: none;
    margin: 0.75rem 0 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}
.ticket-announcement-pick {
    width: 100%;
    display: flex;
    gap: 0.6rem;
    align-items: flex-start;
    padding: 0.75rem;
    background: var(--surface);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
    color: var(--fg);
    font: inherit;
    cursor: pointer;
    text-align: left;
    transition: border-color 0.12s, background 0.12s;
}
.ticket-announcement-pick:hover {
    border-color: var(--accent);
    background: var(--shade-1);
}
.ticket-announcement-pick:focus-visible {
    outline: 2px solid rgba(54, 150, 252, 0.4);
    outline-offset: 2px;
}
.ticket-announcement-pick-body {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    flex: 1 1 auto;
    min-width: 0;
}
.ticket-announcement-pick-title {
    font-weight: 600;
    line-height: 1.3;
}
.ticket-announcement-pick-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    align-items: center;
    font-size: 0.82rem;
}

.user-block {
    display: flex;
    gap: 0.75rem;
    align-items: flex-start;
    margin-bottom: 0.5rem;
}
.user-block .avatar { width: 44px; height: 44px; flex-shrink: 0; }
.user-block-info { display: flex; flex-direction: column; gap: 0.2rem; min-width: 0; }
.user-block-name { color: var(--accent); font-size: 1rem; }
.user-block-mail {
    color: var(--accent);
    font-size: 0.85rem;
    text-decoration: none;
    word-break: break-all;
}
.user-block-mail i { color: var(--muted); margin-right: 0.3rem; }
.user-block-mail:hover { text-decoration: underline; }
.user-block-switch { font-size: 0.85rem; color: var(--accent); margin-top: 0.25rem; }

/* Sidebar form fields — uppercase tiny label + native input underneath. */
.sidebar-field {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    margin-bottom: 0.85rem;
}
.sidebar-field > span {
    color: var(--muted);
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}
.sidebar-field select,
.sidebar-field input[type="text"] {
    width: 100%;
    padding: 0.5em 0.7em;
    font-size: 0.9rem;
    font-family: inherit;
    background: var(--surface);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
    color: var(--fg);
}
/* Read-only value in the sidebar — for system-controlled fields (typically
   ticket.invoice = 'part' / 'complete') where the user shouldn't be able
   to change it. Visually an input-lookalike, but not interactive. */
.sidebar-readonly-value {
    width: 100%;
    padding: 0.5em 0.7em;
    font-size: 0.9rem;
    background: var(--shade-1);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    color: var(--muted);
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
}
.sidebar-field select:disabled,
.sidebar-field input:disabled { background: var(--surface); color: var(--fg); cursor: not-allowed; }
.sidebar-field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem; }

/* Visual parity with native <select>: SearchField-trigger and chip-input
   should look identical to selects when they sit next to each other in
   the sidebar (Tjeneste, Lokasjon, Kategori, CMDB etc.). Same height,
   padding, font-size, border. */
.sidebar-field .search-field-trigger {
    min-height: 0;
    padding: 0.5em 0.7em;
    font-size: 0.9rem;
}
/* `.sidebar-field .chip-input` previously redeclared all the visual tokens
   here — extracted to the canonical `.chip-input` rule in main.css. No
   context-specific overrides needed: the sidebar layout works on the base
   tokens unchanged. */
.sidebar-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 0.3rem;
    min-height: 30px;
    padding: 0.35em 0.5em;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
    background: var(--surface);
}
.sidebar-tags .tag {
    display: inline-flex;
    align-items: center;
    padding: 0.15em 0.55em;
    font-size: 0.8rem;
    background: var(--icon-blue-soft);
    color: var(--accent);
    border-radius: 999px;
}
.sidebar-empty { font-size: 0.85rem; }

.sidebar-timestamps {
    margin-top: 1.25rem;
    padding-top: 0.75rem;
    border-top: 1px solid var(--border);
    font-size: 0.8rem;
}
.sidebar-timestamps > div { display: flex; justify-content: space-between; margin: 0.2rem 0; }
.sidebar-timestamps dt { color: var(--muted); font-weight: 400; }
.sidebar-timestamps dd { margin: 0; color: var(--fg); }

/* ------ Comments — uniform padded shell ------
   Every comment has the same padding + a 2px transparent border so
   the avatar/content alignment is constant regardless of variant.
   Variants (private/solution) only swap the border-color; horizontal
   geometry never shifts. Separation between comments comes from
   `.agent-comments` flex-gap below. */
.comment-flat {
    display: flex;
    gap: 1rem;
    padding: 1.25rem;
    border: 1px solid transparent;
    border-radius: var(--radius);
    position: relative;
    /* content-visibility: auto lets the browser skip rendering of off-screen
       comments. Dramatic speedup on long threads (both initial paint
       and dark-mode toggle, since var()-recompute then avoids running over
       invisible elements). contain-intrinsic-size gives the browser a height
       hint so the scrollbar doesn't jump on hydration. */
    content-visibility: auto;
    contain-intrinsic-size: auto 200px;
}
/* Sibling-element separator rendered between comments by JS
   (renderCommentList). Dashed line that sits in the gap between
   cards. Avoids the content-visibility:auto paint-containment that
   would clip an ::after pseudo-element positioned outside the card. */
.agent-comments { display: flex; flex-direction: column; gap: 0.5rem; }
.comment-sep {
    margin: 0.25rem 1.25rem;
    border: 0;
    border-top: 1px dashed var(--border);
}
/* Suppress separator next to comments that already have a visible
   border (private + solution). Their own border already delineates
   them from neighbours; an extra dashed line in the gap reads as
   redundant. */
.comment-flat.comment-private + .comment-sep,
.comment-flat.comment-solution + .comment-sep,
.comment-sep:has(+ .comment-flat.comment-private),
.comment-sep:has(+ .comment-flat.comment-solution) {
    display: none;
}
/* `content-visibility: auto` creates a containing-block that clips
   absolutely-positioned children — like the ellipsis-dropdown menu. When the
   menu is open, lift the restriction so it can be drawn over the comment
   form below. */
.comment-flat:has(.dropdown-menu:not([hidden])) {
    content-visibility: visible;
    overflow: visible;
    z-index: 110;
    position: relative;
}
/* Newly-appended comments get a subtle tint that fades out. Applied
   both on submit (the user's own new comment) and on poll (from others).
   Negative side margins "eat" into `.agent-ticket-main`'s horizontal
   padding so the background extends slightly beyond the text — the frame
   becomes clearer without the comment column narrowing. */
.comment-flat.is-new {
    animation: comment-flash 3.5s ease-out;
    padding-left: 0.9rem;
    padding-right: 0.9rem;
    margin-left: -0.9rem;
    margin-right: -0.9rem;
    border-radius: var(--radius);
    border-bottom-color: transparent;
}
@keyframes comment-flash {
    0%   { background: var(--icon-blue-soft); }
    100% { background: transparent; }
}

/* System notice in the comment thread — data source:
   hd_ticket_history.type='system'. Matches old app's `.system-message`
   style (muted, small, centred). Rendered by renderComment() when a
   comment row carries type='system'. No avatar / header / menu. */
.comment-system {
    display: flex;
    justify-content: center;
    align-items: baseline;
    gap: 0.5rem;
    padding: 0.65rem 0;
    color: var(--muted);
    font-size: 0.8rem;
    text-align: center;
}
.comment-system time { font-variant-numeric: tabular-nums; font-size: 0.75rem; }
.comment-system-body { color: var(--muted); }
.comment-system-body a { color: var(--accent); text-decoration: none; }
.comment-system-body a:hover { text-decoration: underline; }

/* Toggle-hiding of system comments + adjacent separator. Activated
   by the [data-action="toggle-system"] button in the topbar; persisted in
   localStorage under `fipo_show_system_comments`. Default state is OFF
   (data-attribute set) so system messages don't add noise in the normal
   flow. Also hides .comment-sep right BEFORE a system comment so we don't
   get a double dashed line when sep + system + sep are all adjacent. */
.agent-comments[data-hide-system="1"] [data-comment-type="system"],
.agent-comments[data-hide-system="1"] .comment-sep:has(+ [data-comment-type="system"]) {
    display: none;
}

.comment-flat .avatar { width: 40px; height: 40px; flex-shrink: 0; }
.comment-flat-content { flex: 1; min-width: 0; }
.comment-flat-head {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 0.4rem;
    font-size: 0.9rem;
    /* Wrap on narrow viewports so a long author name + badge doesn't
     * push the timestamp + menu trigger off the right edge. With wrap,
     * the time drops to a second line aligned to the row's right edge
     * (margin-left: auto still works on a wrapped line). */
    flex-wrap: wrap;
    row-gap: 0.2rem;
}
.comment-flat-head strong { color: var(--fg); font-size: 0.95rem; flex: 0 0 auto; }
/* Time pushed to the row's right edge regardless of whether a badge
   sits between strong and time — keeps timestamps vertically aligned
   across the comment list. */
.comment-flat-time { color: var(--muted); font-size: 0.85rem; margin-left: auto; }
.comment-flat-timereg {
    color: var(--accent);
    font-size: 0.85rem;
    font-variant-numeric: tabular-nums;
    cursor: pointer;
    text-decoration: none;
}
.comment-flat-timereg:hover { text-decoration: underline; }

/* Per-comment ellipsis trigger — small icon-button in the header row.
   The dropdown panel itself uses the generic .dropdown-menu from main.css. */
.comment-menu-trigger {
    width: 28px;
    height: 28px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: 0;
    border-radius: 50%;
    color: var(--muted);
    font-size: 0.95rem;
    cursor: pointer;
}
.comment-menu-trigger:hover { background: var(--shade-1); color: var(--fg); }
.comment-flat-title {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin: 0.25rem 0 0.75rem;
    font-size: 1.15rem;
    font-weight: 600;
    color: var(--fg);
}
.comment-flat-title-prefix { color: var(--muted); flex-shrink: 0; }
.comment-flat-title-text { min-width: 0; word-break: break-word; }
/* Pencil button that swaps the title to inline-edit. Hidden by default,
   appears on hover/focus over the whole title row so the agent discovers
   the affordance without it dominating at rest. */
.comment-flat-title-edit {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    background: transparent;
    border: 0;
    border-radius: 50%;
    color: var(--muted);
    cursor: pointer;
    opacity: 0;
    transition: opacity 0.12s, background 0.12s, color 0.12s;
    flex-shrink: 0;
}
.comment-flat-title:hover .comment-flat-title-edit,
.comment-flat-title-edit:focus-visible {
    opacity: 1;
}
.comment-flat-title-edit:hover {
    background: var(--shade-1);
    color: var(--accent);
}
/* Input when edit is active. Matches the title size so the height doesn't jump. */
.comment-flat-title-input {
    flex: 1;
    min-width: 0;
    padding: 0.2rem 0.5rem;
    font-size: inherit;
    font-weight: inherit;
    font-family: inherit;
    color: var(--fg);
    background: var(--surface);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
}
.comment-flat-title-input:focus {
    outline: 2px solid rgba(54, 150, 252, 0.4);
    outline-offset: 0;
    border-color: var(--accent);
}
.comment-flat-body { color: var(--fg); }
.comment-initial .comment-flat-body { color: var(--muted); }
/* Footnote-style provenance line under the initial ticket message —
   "via e-post" / "via brukerportal" / … Subtle by design: small,
   italic, muted, no icon. The "Se hele e-postmelding"-action lives
   in the ••• dropdown in the header instead, parity with how reply
   comments expose their per-comment actions. */
.comment-initial-source {
    margin-top: 1.25rem;
    font-size: 0.78rem;
    font-style: italic;
    color: var(--muted);
}
/* Comment variant-styling for the agent-portal's flat layout. Scoped
   to `.comment-flat.comment-X` so it doesn't bleed into the user-
   portal's `<article class="surface comment-card card">`-shape (which
   has its own design — see design.md §"Two shells"). Default
   .comment-flat stays flat; only private gets a red callout-frame
   so internal communication is impossible to confuse with a regular
   reply. The old `· INTERNT` ::after-pseudo was removed 2026-04-28 —
   the .comment-type-private badge in the header carries the label. */
.comment-flat.comment-private  { border-color: var(--icon-red-line); }
.comment-flat.comment-solution { border-color: var(--icon-green); }

/* ------ Agent ticket list (new layout) ------ */
.agent-list-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1rem;
}
.toolbar-title { display: flex; align-items: baseline; gap: 1rem; flex-wrap: wrap; }
.toolbar-title h1 { margin: 0; font-size: 1.65rem; font-weight: 600; }

.toolbar-view-toggle {
    display: inline-flex;
    background: var(--shade-1);
    border-radius: 999px;
    padding: 3px;
    gap: 2px;
}
/* View-toggle pill is NOT a .btn — it's a segmented control. Overrides the
   default button styling to look like a rounded pill. */
.toolbar-view-toggle button {
    background: transparent;
    color: var(--muted);
    border: 0;
    height: auto;
    padding: 0.35rem 0.85rem;
    font-size: 0.9rem;
    font-weight: 500;
    border-radius: 999px;
    cursor: pointer;
}
.toolbar-view-toggle button:hover { background: transparent; color: var(--fg); }
.toolbar-view-toggle button.active { background: var(--surface); color: var(--accent); box-shadow: var(--shadow-sm); }

.toolbar-actions { display: flex; gap: 0.5rem; align-items: center; }
/* Button styling lives in main.css §Button system. Use:
   - refresh:  <button class="btn btn-ghost btn-icon"><i class="fal fa-sync-alt"></i></button>
   - filter:   <button class="btn btn-ghost" [.active when applied]><i/><span>Filter</span></button>
   - ny sak:   <a class="btn btn-success" href="..."><i/> Ny sak</a>
*/

.agent-ticket-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.5rem; }

.agent-ticket-row {
    display: grid;
    /* Fixed widths so every row's meta column aligns with the next.
       Long service / location names truncate with ellipsis instead of
       expanding the column.
       Column order matches old app (ticket_list_item.jsr): avatar | body
       (title/submitter/times) | status-pill | meta-details (tekniker/
       type/tjeneste/lokasjon). Status sits between body and meta so it
       stands alone as a visual anchor, and meta details are right-aligned. */
    grid-template-columns: 52px minmax(0, 1fr) 130px 320px;
    grid-template-areas: "avatar body status meta";
    gap: 1rem;
    align-items: flex-start;
    padding: 0.9rem 1rem;
    color: var(--fg);
    text-decoration: none;
    /* Surface-tokens + hover-lift come from the shared :is() block
       in main.css — see "CANONICAL ROW-SURFACE". Only structure here. */
}
.agent-ticket-row:hover .agent-ticket-quickview { opacity: 0.65; }

/* Alarm-tier surfaces (priority = critical or high) get a red accent
   border-left + badge so the row stands out visually after the backend
   already sorts it to the top. Same visual for both tiers — the badge
   label inside differentiates them. */
.agent-ticket-row--critical,
.agent-ticket-row--high {
    box-shadow: inset 4px 0 0 0 var(--danger, #d04141);
}
.agent-ticket-priority-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    background: var(--danger, #d04141);
    color: #fff;
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    padding: 0.1rem 0.45rem;
    border-radius: 999px;
    margin-right: 0.35rem;
    flex-shrink: 0;
}
.agent-ticket-priority-badge i { font-size: 0.78rem; }

/* Inline quickview icon — sits right after the title, hover-reveal only. */
.agent-ticket-quickview {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    margin-left: 0.5rem;
    padding: 0;
    background: transparent;
    border: 0;
    color: var(--muted);
    cursor: pointer;
    opacity: 0;
    transition: opacity 0.15s, color 0.15s;
    font-size: 0.9rem;
    vertical-align: middle;
}
.agent-ticket-quickview:hover { color: var(--accent); opacity: 1 !important; }
.agent-ticket-quickview:focus-visible { opacity: 1; }
.agent-ticket-quickview { flex-shrink: 0; }

.agent-ticket-avatar { grid-area: avatar; }
.agent-ticket-avatar .avatar {
    width: 44px; height: 44px;
    font-size: 0.9rem;
}

.agent-ticket-body { grid-area: body; min-width: 0; }
.agent-ticket-title {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    color: var(--accent);
    font-weight: 600;
    font-size: 1rem;
    margin-bottom: 0.15rem;
    min-width: 0;
}
.agent-ticket-title-text {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}
.agent-ticket-submitter { font-size: 0.88rem; margin-bottom: 0.15rem; }
.agent-ticket-submitter strong { color: var(--fg); }
.agent-ticket-times { font-size: 0.78rem; }

.agent-ticket-meta {
    grid-area: meta;
    display: grid;
    grid-template-columns: auto 1fr;
    column-gap: 0.5rem;
    row-gap: 0.15rem;
    font-size: 0.85rem;
}
.agent-ticket-meta > div { display: contents; }
.agent-ticket-meta .label { color: var(--muted); white-space: nowrap; }
.agent-ticket-meta > div > span:last-child {
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.agent-ticket-row .status-pill {
    grid-area: status;
    align-self: flex-start;
    /* Center-align in its own column — it's the visual anchor between
       body and meta, not a right-justified afterthought. */
    justify-self: start;
}

@media (max-width: 900px) {
    .agent-ticket-row {
        grid-template-columns: 52px 1fr auto;
        grid-template-areas:
            "avatar body status"
            "avatar meta meta";
    }
}

/* Narrow phones: long technician / service / location names truncate
 * with ellipsis on the desktop layout because every meta value sits
 * in a fixed-width grid cell. Below 480px we let values wrap to a
 * second line instead — preserves full information and is acceptable
 * vertically on a tickets list (rows are tappable cards, height varies
 * naturally with content). */
@media (max-width: 480px) {
    .agent-ticket-meta > div > span:last-child {
        white-space: normal;
        overflow: visible;
        text-overflow: clip;
    }
}

/* ------ Settings landing: horizontal tiles with solid colored icon-badges ------
   Separate from the generic .tile system (which is icon-above-title with soft-tint).
   These are icon-left + title + subtitle + chevron, 2-column on desktop. */
.settings-tiles {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 0.85rem;
    margin-bottom: 2rem;
}
@media (max-width: 720px) {
    .settings-tiles { grid-template-columns: 1fr; }
}

.settings-tile {
    /* Surface-tokens + hover-lift inherited from the :is() block under
       "CANONICAL ROW-SURFACE" in main.css. Only structure here. */
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 1rem 1.25rem;
    color: var(--fg);
    text-decoration: none;
}

/* Settings tile icon badge — soft-tinted background per docs/design.md
   §Colored function icons ("Combine icon-color with a matching
   soft-tinted background for a tag-like look"). Colors carried via
   .icon-blue/-green/-amber/-purple/-red which set --icon-bg + --icon-fg
   globally in main.css §Function-icon palette. */
.settings-tile-icon {
    flex: 0 0 auto;
    width: 44px;
    height: 44px;
    border-radius: 10px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 1.15rem;
    background: var(--icon-bg, var(--icon-blue-soft));
    color: var(--icon-fg, var(--icon-blue));
}

.settings-tile-body {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
}
.settings-tile-title {
    font-size: 1.02rem;
    font-weight: 600;
    color: var(--fg);
    line-height: 1.2;
}
.settings-tile-subtitle {
    color: var(--muted);
    font-size: 0.88rem;
    line-height: 1.3;
}
.settings-tile-chevron {
    flex: 0 0 auto;
    color: var(--muted);
    font-size: 1rem;
}

/* ------ Settings landing: section-grouped mini-tiles ------
   Calm layout — typography + spacing + hover carry the interface, not
   color. Section headings are plain type with a muted icon; mini-tiles
   are neutral cards whose icons turn accent-blue on hover. Access-gated
   per tile; sections with zero visible tiles are hidden entirely.

   See docs/design.md §Core principles #1 "Calm over shouty" and
   §Colored function icons ("Inside dense lists or tables, icons should
   stay currentColor / neutral — colored icons would create visual noise."). */
.settings-landing {
    display: flex;
    flex-direction: column;
    gap: 1.75rem;
    margin-bottom: 2rem;
}

/* ------ Endringslogg (/agent/settings/changelog) ------
   Plain page (no card chrome around versions — they sit on the
   page background with a hairline divider between them).
   Trivial single-property styles are inlined in the view file;
   the rules here are the multi-property ones that define the
   visual pattern. */
.changelog-list {
    display: flex;
    flex-direction: column;
    gap: 2rem;
}
.changelog-version + .changelog-version {
    /* Hairline separator between versions instead of a card border. */
    padding-top: 2rem;
    border-top: 1px solid var(--border);
}
.changelog-version-title {
    margin: 0 0 0.4rem 0;
    display: flex;
    align-items: baseline;
    gap: 0.6rem;
    font-size: 1.15rem;
    font-weight: 600;
}
/* Section titles use the standard colored-function-icon palette per
   design.md: green for "create / add" (Ny funksjonalitet), blue for
   "primary / info" (Forbedringer), red for "danger / fix"
   (Feilrettinger). Tone class is added per-call from the view. */
.changelog-section-title {
    margin: 0 0 0.5rem 0;
    font-size: 0.78rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}
.changelog-section-green { color: var(--icon-green); }
.changelog-section-blue  { color: var(--icon-blue); }
.changelog-section-red   { color: var(--icon-red); }
.changelog-items {
    margin: 0;
    padding-left: 1.25rem;
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    line-height: 1.5;
}
.settings-section-head {
    display: block;
    font-size: 0.78rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--muted);
    margin: 0 0 0.5rem;
    padding-left: 0.1rem;
}

/* Default settings-tiles: 2 columns (base tile is roomy). Overrides
   the 2-column hard rule on the base class so the landing can go up
   to 3 columns comfortably via the `-sm` modifier. */
.settings-tiles {
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
}

/* Compact tile grid: up to 3 columns across the content-narrow (900px)
   landing — minmax chosen so 2 tiles fit under ~640px, 3 above. Tiles
   never exceed 3-wide because the parent is capped at 900px. */
.settings-tiles.settings-tiles-sm {
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    gap: 0.6rem;
    margin-bottom: 0;
}

/* Large-tile grid for the collapsed "Mer" section (Katalog + System).
   2-column to match the original 6-tile landing, so Katalog + System
   look the same they did before. */
.settings-tiles.settings-tiles-lg {
    grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
    gap: 0.75rem;
    margin-bottom: 0;
}

/* Compact tile variant: smaller icon, subtitle + chevron preserved.
   Extends .settings-tile (same hover/shadow/radius) per docs/design.md
   §DRY mandate — modifier, not a parallel class. Soft-tinted icon
   badge via .icon-blue/-green/-amber/-purple/-red carries meaning
   (see §Colored function icons). */
.settings-tile.settings-tile-sm {
    gap: 0.7rem;
    padding: 0.75rem 0.9rem;
}
.settings-tile.settings-tile-sm .settings-tile-icon {
    width: 36px;
    height: 36px;
    border-radius: 8px;
    font-size: 0.95rem;
    background: var(--icon-bg, var(--icon-blue-soft));
    color: var(--icon-fg, var(--icon-blue));
}
.settings-tile.settings-tile-sm .settings-tile-title {
    font-size: 0.92rem;
    font-weight: 600;
    line-height: 1.2;
}
.settings-tile.settings-tile-sm .settings-tile-subtitle {
    font-size: 0.8rem;
    line-height: 1.3;
}
.settings-tile.settings-tile-sm .settings-tile-chevron {
    font-size: 0.8rem;
}


/* ------ Settings tabs — horizontal underline-style, used inside each settings sub-page ------ */
.settings-tabs {
    display: flex;
    gap: 0.25rem;
    border-bottom: 1px solid var(--border);
    margin-bottom: 1.25rem;
    overflow-x: auto;
}
.settings-tab {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.75rem 1rem;
    color: var(--muted);
    text-decoration: none;
    /* Reset browser-default `<button>` chrome so the same class works
       on both `<a>` (existing usage) and `<button>` (modal-tab usage).
       Only the bottom-border is part of the design — the top/left/right
       defaults must go. */
    background: transparent;
    border: 0;
    border-bottom: 2px solid transparent;
    font: inherit;
    font-size: 0.95rem;
    white-space: nowrap;
    cursor: pointer;
    transition: color 0.15s, border-color 0.15s;
}
.settings-tab:hover { color: var(--fg); }
.settings-tab.active {
    color: var(--accent);
    border-bottom-color: var(--accent);
    font-weight: 600;
}
.settings-tab i { font-size: 0.95rem; }

.settings-tab-panel { min-height: 200px; }

/* ------ Log filter bar (used in Hendelseslogg + Feillogg tabs) ------ */
.log-filter {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    padding: 1rem;
    margin-bottom: 1rem;
}
.log-filter-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 0.75rem;
    align-items: end;
}
.log-filter label {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    font-size: 0.85rem;
}
.log-filter-label {
    color: var(--muted);
    font-weight: 500;
}
.log-filter input,
.log-filter select {
    height: 34px;
    padding: 0 0.6rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    color: var(--fg);
    font-size: 0.9rem;
}
.log-filter input:focus,
.log-filter select:focus {
    outline: 2px solid rgba(54, 150, 252, 0.4);
    border-color: var(--accent);
}
.log-filter-actions {
    display: flex;
    gap: 0.5rem;
    justify-self: end;
    align-self: end;
}

/* ------ Log result meta + table ------ */
.log-result-meta {
    margin-bottom: 0.5rem;
    font-size: 0.85rem;
}
.log-truncated {
    margin-top: 0.75rem;
    font-size: 0.85rem;
}

/* ------ .mail-row (structural — grid only) -------------------------
   Used by: /agent/settings/departments/{id}/inbox + /outbox.
   Card pattern derived from .merc-order-row: icon-tile on the left,
   body in the middle, status and actions on the right, optional
   detail row at the bottom spanning full width. Surface design
   (background/border/shadow/radius) comes from the shared .surface
   utility — do NOT duplicate those tokens here. */
.mail-row {
    display: grid;
    grid-template-columns: 36px minmax(0, 1fr) auto;
    grid-template-areas:
        "icon body   status"
        "icon body   actions"
        "detail detail detail";
    column-gap: 0.85rem;
    row-gap: 0.4rem;
    padding: 0.85rem 1rem;
    align-items: start;
}
.mail-row-icon {
    grid-area: icon;
    width: 36px;
    height: 36px;
    border-radius: 8px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 1rem;
    background: var(--icon-bg, var(--icon-blue-soft));
    color: var(--icon-fg, var(--icon-blue));
}
.mail-row-body {
    grid-area: body;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 0.18rem;
}
.mail-row-title {
    font-weight: 600;
    color: var(--fg);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.mail-row-meta {
    font-size: 0.85rem;
    color: var(--muted);
    display: flex;
    flex-wrap: wrap;
    gap: 0.15rem 0.85rem;
}
.mail-row-meta strong {
    color: var(--fg);
    font-weight: 600;
}
.mail-row-status {
    grid-area: status;
    justify-self: end;
    display: flex;
    gap: 0.35rem;
    flex-wrap: wrap;
}
.mail-row-actions {
    grid-area: actions;
    justify-self: end;
    display: flex;
    gap: 0.4rem;
    flex-wrap: wrap;
}
.mail-row-detail {
    grid-area: detail;
    margin: 0;
    padding: 0.65rem 0.85rem;
    background: var(--shade-1);
    border-radius: var(--radius);
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.8rem;
    line-height: 1.5;
    color: var(--fg);
    white-space: pre-wrap;
    overflow-x: auto;
}

@media (max-width: 600px) {
    .mail-row {
        grid-template-columns: 36px minmax(0, 1fr);
        grid-template-areas:
            "icon body"
            "icon status"
            ".    actions"
            "detail detail";
        row-gap: 0.5rem;
    }
    .mail-row-status,
    .mail-row-actions {
        justify-self: start;
    }
}

/* ------ .mail-detail-drawer (drawer-body content) ----------------
   Used by mail-detail-drawer.js — opens when a .mail-row is clicked
   under /agent/settings/departments/{id}/inbox or /outbox.
   Distinct prefix (not .mail-drawer*) to avoid colliding with
   mail-account-drawer.js, which owns .mail-drawer-* for account
   editing. */
.mail-detail-drawer {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 1.25rem;
}
.mail-detail-drawer-head {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.5rem;
}
.mail-detail-drawer-subject {
    margin: 0;
    font-size: 1.05rem;
    font-weight: 600;
    color: var(--fg);
    text-align: left;
    word-break: break-word;
}
.mail-detail-drawer-status {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
}
.mail-detail-drawer-meta {
    margin: 0;
    display: grid;
    grid-template-columns: minmax(110px, max-content) 1fr;
    gap: 0.4rem 1rem;
    font-size: 0.9rem;
}
.mail-detail-drawer-meta-row {
    display: contents;
}
.mail-detail-drawer-meta dt {
    color: var(--muted);
    font-weight: 500;
}
.mail-detail-drawer-meta dd {
    margin: 0;
    color: var(--fg);
    word-break: break-word;
    min-width: 0;
}
.mail-detail-drawer-section {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}
.mail-detail-drawer-section-title {
    margin: 0;
    font-size: 0.78rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--muted);
}
.mail-detail-drawer-response {
    margin: 0;
    padding: 0.75rem 0.85rem;
    background: var(--shade-1);
    border-radius: var(--radius);
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.82rem;
    line-height: 1.5;
    color: var(--fg);
    white-space: pre-wrap;
    overflow-x: auto;
}
/* Plain-text body (inbox mail_text, outbox push_message). Preserves
   line breaks but uses normal font for readability. */
.mail-detail-drawer-body-text {
    margin: 0;
    padding: 0.85rem 1rem;
    background: var(--shade-1);
    border-radius: var(--radius);
    font-size: 0.92rem;
    line-height: 1.55;
    color: var(--fg);
    white-space: pre-wrap;
    word-break: break-word;
    max-height: 480px;
    overflow: auto;
}
/* HTML-rendered email body (outbox mail_message). Sandboxed iframe
   via srcdoc so the email's own inline CSS / fonts / image widths
   stay scoped, and scripts / form-posts from inside are blocked. */
.mail-detail-drawer-body-iframe {
    width: 100%;
    height: 360px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: white;
}
.mail-detail-drawer-actions {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
    margin-top: 0.25rem;
}

.log-table {
    width: 100%;
    border-collapse: collapse;
    overflow: hidden;
    font-size: 0.88rem;
}
.log-table th {
    text-align: left;
    padding: 0.65rem 0.75rem;
    background: var(--shade-1);
    color: var(--muted);
    font-weight: 500;
    border-bottom: 1px solid var(--border);
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.02em;
}
.log-table td {
    padding: 0.55rem 0.75rem;
    border-bottom: 1px solid var(--border);
    vertical-align: top;
}
.log-table tr:last-child td { border-bottom: none; }
.log-row:hover { background: var(--shade-1); }

.log-time { white-space: nowrap; color: var(--muted); font-variant-numeric: tabular-nums; font-size: 0.82rem; }
.log-user { white-space: nowrap; }
.log-domain .log-pill {
    display: inline-block;
    padding: 0.12rem 0.5rem;
    background: var(--icon-blue-soft);
    color: var(--icon-blue);
    border-radius: 999px;
    font-size: 0.75rem;
    font-weight: 600;
}
.log-type { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.82rem; }
.log-tag code {
    font-size: 0.8rem;
    background: var(--shade-1);
    padding: 0.1rem 0.35rem;
    border-radius: var(--radius);
    color: var(--muted);
}
.log-title { font-weight: 500; }
.log-message { color: var(--muted); }

.log-expand { text-align: right; width: 40px; }
.log-expand-btn {
    background: transparent;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    width: 28px;
    height: 28px;
    padding: 0;
    cursor: pointer;
    color: var(--muted);
}
.log-expand-btn:hover { color: var(--accent); border-color: var(--accent); }

.log-row-data td { padding: 0; background: var(--shade-1); }
.log-data {
    margin: 0;
    padding: 0.75rem 1rem;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.8rem;
    color: var(--fg);
    white-space: pre-wrap;
    word-break: break-word;
    line-height: 1.5;
}

/* Severity pills — feillogg column */
.log-severity-pill {
    display: inline-block;
    padding: 0.12rem 0.55rem;
    border-radius: 999px;
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.02em;
}
.log-severity-pill.severity-red    { background: var(--icon-red-soft);   color: var(--icon-red); }
.log-severity-pill.severity-amber  { background: var(--icon-amber-soft); color: var(--icon-amber); }
.log-severity-pill.severity-blue   { background: var(--icon-blue-soft);  color: var(--icon-blue); }

/* ------ Mobile: stack table columns ------ */
@media (max-width: 720px) {
    .log-table thead { display: none; }
    .log-table tr { display: block; padding: 0.75rem; border-bottom: 1px solid var(--border); }
    .log-table td { display: block; padding: 0.15rem 0; border: none; }
    .log-table td.log-expand { position: absolute; right: 0.75rem; margin-top: -1.75rem; }
    .log-row { position: relative; }
}

/* ------ Links admin head ------ */
.links-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    margin-bottom: 1rem;
    flex-wrap: wrap;
}
.links-head .muted { font-size: 0.88rem; }

/* (.link-item / .link-icon / .link-url / .link-scope / .link-flag /
   .link-flags removed 2026-04-25 — the links list now uses .list-item
   with .badge for flags/scope.) */

/* `.btn-icon-ghost` moved to main.css so the user-portal (cart,
   notification rows, etc.) also gets styling. */

/* ------ Link create/edit form (inside Modal) ------ */
.link-form {
    display: flex;
    flex-direction: column;
    gap: 0.85rem;
}
.link-form-feedback {
    background: var(--icon-red-soft);
    color: var(--icon-red);
    padding: 0.65rem 0.85rem;
    border-radius: var(--radius);
    font-size: 0.85rem;
}
.link-form-field {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
}
.link-form-label {
    font-size: 0.85rem;
    font-weight: 500;
    color: var(--fg);
}
.link-form-label .required { color: var(--icon-red); }
.link-form input[type="text"],
.link-form input[type="url"],
.link-form select {
    height: 38px;
    padding: 0 0.7rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    color: var(--fg);
    font-size: 0.9rem;
}
.link-form input:focus,
.link-form select:focus {
    outline: 2px solid rgba(54, 150, 252, 0.4);
    border-color: var(--accent);
}
.link-form-hint {
    font-size: 0.78rem;
    color: var(--muted);
}

.link-form-flags {
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 0.6rem 0.85rem;
    margin: 0.25rem 0 0;
}
.link-form-flags legend {
    padding: 0 0.4rem;
    font-size: 0.82rem;
    font-weight: 500;
    color: var(--muted);
}
.link-form-flags .checkbox {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    font-size: 0.9rem;
    padding: 0.25rem 0;
    cursor: pointer;
}
.link-form-flags .checkbox input { margin: 0; }

.link-form-actions {
    display: flex;
    justify-content: flex-end;
    gap: 0.5rem;
    margin-top: 0.25rem;
}

/* ------ Scheduler tab (system → Planlagte oppgaver) ------ */
.scheduler-intro { margin-bottom: 0.75rem; font-size: 0.88rem; }
.scheduler-item code {
    background: var(--shade-1);
    color: var(--muted);
    padding: 0.08rem 0.35rem;
    border-radius: var(--radius);
    font-size: 0.78rem;
}
.scheduler-run-label {
    color: var(--muted);
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}
.scheduler-run-value {
    font-size: 0.85rem;
    color: var(--fg);
    font-variant-numeric: tabular-nums;
}

.badge-on {
    display: inline-flex; align-items: center; gap: 0.3rem;
    padding: 0.12rem 0.55rem;
    background: var(--icon-green-soft);
    color: var(--icon-green);
    border-radius: 999px;
    font-size: 0.75rem;
    font-weight: 600;
}
.badge-off {
    display: inline-block;
    padding: 0.12rem 0.55rem;
    background: var(--shade-1);
    color: var(--muted);
    border-radius: 999px;
    font-size: 0.75rem;
}

.status-badge {
    display: inline-block;
    padding: 0.12rem 0.55rem;
    border-radius: 999px;
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.02em;
}
.status-badge.status-green { background: var(--icon-green-soft); color: var(--icon-green); }
.status-badge.status-red   { background: var(--icon-red-soft);   color: var(--icon-red); }
.status-badge.status-blue  { background: var(--icon-blue-soft);  color: var(--icon-blue); }
.status-badge.status-amber { background: var(--icon-amber-soft); color: var(--icon-amber); }

/* Scheduler detail modal */
.scheduler-detail {
    display: grid;
    grid-template-columns: 140px 1fr;
    gap: 0.35rem 1rem;
    margin: 0;
}
.scheduler-detail dt { color: var(--muted); font-size: 0.82rem; font-weight: 500; }
.scheduler-detail dd { margin: 0; font-size: 0.88rem; word-break: break-word; }
.scheduler-detail code {
    background: var(--shade-1);
    padding: 0.08rem 0.4rem;
    border-radius: var(--radius);
    font-size: 0.82rem;
}
.scheduler-feedback-head { margin: 1.25rem 0 0.4rem; font-size: 0.95rem; }

/* Schedule editor inside the detail modal — separates from the dl
   above and from the feedback panel below. .form-section-title gives
   the small uppercase heading used elsewhere in admin pages. */
.scheduler-edit-head { margin: 1.5rem 0 0.6rem; }
.scheduler-edit { margin: 0; }
.scheduler-next-row { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.5rem; margin: 0.25rem 0 0; }
.scheduler-next-row strong { color: var(--fg); font-weight: 600; }
.scheduler-cron-pill { color: var(--muted); font-size: 0.82rem; }
.scheduler-feedback {
    background: var(--shade-1);
    border-radius: var(--radius);
    padding: 0.75rem 1rem;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.8rem;
    white-space: pre-wrap;
    word-break: break-word;
    max-height: 300px;
    overflow-y: auto;
    margin: 0;
}

@media (max-width: 720px) {
    .scheduler-detail { grid-template-columns: 1fr; gap: 0.1rem 0; }
    .scheduler-detail dt { margin-top: 0.5rem; }
}

/* ------ Admin list (used by settings CRUD) ------
   Uses the SAME grid system as .list-item (main.css §Reusable list
   primitives) with one extra fixed column for inline action buttons
   (pen/trash/etc.) — since admin rows carry multiple actions, a <div>
   not an <a>. Fixed columns mean every row aligns vertically.

   NOTE: docs/design.md §Reusable list primitives is the source of truth —
   do NOT introduce new per-domain row classes. Extend this pattern via
   modifier classes or CSS custom properties instead.

   The `--row-accent` custom property draws a 4px left border in the given
   color. Use this for status/type coding INSTEAD of a prefix pill so
   titles line up across rows. Fall back: transparent (no accent). */
.admin-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    margin-bottom: 1rem;
    flex-wrap: wrap;
}
.admin-head .muted { font-size: 0.88rem; flex: 1 1 280px; }
.admin-head-actions {
    display: flex;
    align-items: center;
    gap: 0.75rem;
}
.admin-toggle {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    font-size: 0.85rem;
    color: var(--muted);
    cursor: pointer;
}

/* ------ Generic admin form (used in modals) ------ */
/* (.admin-list / .admin-item / .admin-body / .admin-title / .admin-subtitle /
   .admin-meta / .admin-actions / .badge-deleted / .admin-item.accent-*
   removed 2026-04-25 — all CRUD rows now use .list-item.list-item-with-actions
   with the .badge component for flags. See docs/components/list-item.md + badge.md.) */
.admin-form {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}
.admin-form-feedback {
    background: var(--icon-red-soft);
    color: var(--icon-red);
    padding: 0.65rem 0.85rem;
    border-radius: var(--radius);
    font-size: 0.85rem;
}
.admin-form-field {
    display: flex;
    flex-direction: column;
    /* Label–input gap is intentionally tight (0.25rem) so the pair reads
       as one unit. Field-to-field gap on .admin-form is 1rem — the visual
       hierarchy must stay label → input → break → next label → next input.
       See design.md §Forms. */
    gap: 0.25rem;
}
.admin-form-label {
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--muted);
    /* Slight uppercase + letterspacing makes labels read clearly as
       metadata for the input below, not as inline text. */
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.admin-form-label .required { color: var(--icon-red); }
.admin-form input[type="text"],
.admin-form input[type="password"],
.admin-form input[type="email"],
.admin-form input[type="url"],
.admin-form input[type="tel"],
.admin-form input[type="search"],
.admin-form input[type="number"],
.admin-form input[type="date"],
.admin-form input[type="datetime-local"],
.admin-form input[type="time"],
.admin-form input[type="week"],
.admin-form input[type="month"],
.admin-form select {
    height: 38px;
    /* Extra right padding gives the native chevron breathing room from
       the right border — the default 0.7rem made the arrow look glued
       to the edge of the input. */
    padding: 0 1.8rem 0 0.7rem;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
    background: var(--surface);
    color: var(--fg);
    font-size: 0.9rem;
    font-family: inherit;
}
.admin-form textarea {
    padding: 0.5rem 0.7rem;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
    background: var(--surface);
    color: var(--fg);
    font-size: 0.9rem;
    font-family: inherit;
    resize: vertical;
    min-height: 4.5em;
}
.admin-form input:focus,
.admin-form textarea:focus,
.admin-form select:focus {
    outline: 2px solid rgba(54, 150, 252, 0.4);
    border-color: var(--accent);
}
.admin-form-hint {
    font-size: 0.78rem;
    color: var(--muted);
}
.admin-form-row {
    display: flex;
    gap: 0.75rem;
}
/* In a row, each field shares the width equally and can shrink — without
   this, a <select> with long option labels (e.g. lokasjons-navn) inflates
   the field's natural width and pushes the row past the modal's right edge. */
.admin-form-row > .admin-form-field {
    flex: 1 1 0;
    min-width: 0;
}
.admin-form-row > .admin-form-field > input,
.admin-form-row > .admin-form-field > select,
.admin-form-row > .admin-form-field > textarea {
    width: 100%;
}
.admin-form-field-grow { flex: 1 1 auto; min-width: 0; }
.admin-form-field-wide { flex: 2; min-width: 0; }
.admin-form-field-narrow { flex: 0 0 120px; }
/* Mobile: side-by-side fields cram below ~600px (a 120px-narrow + a
 * grow on a 280px form-modal leaves the grow at 160px-ish, with text
 * jamming labels). Stack vertically so each field gets full width.
 * Also widen the "narrow" field so a coord pair / zip code aren't
 * locked to 120px when the column collapses to a single column. */
@media (max-width: 600px) {
    .admin-form-row { flex-direction: column; gap: 0.5rem; }
    .admin-form-field-narrow { flex: 1 1 auto; }
}

/* Generic fieldset inside admin-form — override browser default so it
   matches the surrounding card-style layout (rounded border, lifted
   legend, no stark gray line). */
.admin-form-fieldset {
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 0.75rem 1rem 1rem;
    margin: 0;
    background: var(--shade-1);
}
.admin-form-fieldset legend {
    padding: 0 0.5rem;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--muted);
}

/* .admin-form-actions canonical rule lives in main.css (so user-portal
   modals get right-aligned buttons too — see design.md §Action bar). */

/* Condition/action rows inside the autoassign rule-editor modal —
   each row is [field-dropdown] [op] [value-control] [remove-button].
   Flex so the value-control flexes to fill, with stable gap between
   parts. Mirrors the pattern other admin row-editors use (autoassign
   originally; might be extracted to a shared `.editor-row` later if
   another view needs the same layout). */
.rule-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.5rem;
}
.rule-row > select,
.rule-row > span[data-value-host] > select,
.rule-row > span[data-value-host] > .search-field,
.rule-row > span[data-params-host] > select,
.rule-row > span[data-params-host] > .search-field {
    flex: 1 1 0;
    min-width: 0;
}
.rule-row > span[data-value-host],
.rule-row > span[data-params-host] {
    flex: 1 1 0;
    min-width: 0;
    display: flex;
}
.rule-row .rule-row-op {
    flex: 0 0 auto;
    padding: 0 0.25rem;
    font-weight: 600;
}
.rule-row [data-action="remove-row"] {
    flex: 0 0 auto;
}
/* Aligns the "Aktivert"-toggle vertically with the number-input next
   to it inside the rule-editor modal. The toggle has no
   `.admin-form-label`, so without padding-top it would sit above the
   input's label-aligned text. */
.rule-form-toggle-align {
    margin-top: 1.4rem;
}

/* "+ Legg til X"-button inside an editor section. Dashed accent
   outline so it reads as "add another row here" without competing
   with the form's primary action. Standard pattern for repeatable-row
   editors; visually distinct from inputs (which have solid borders)
   and from primary buttons (which are filled). */
.btn-add-row {
    width: 100%;
    padding: 0.55rem 0.9rem;
    border: 1px dashed var(--accent);
    border-radius: var(--radius);
    background: transparent;
    color: var(--accent);
    font: inherit;
    font-size: 0.85rem;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    transition: background 0.12s, color 0.12s;
}
.btn-add-row:hover {
    background: rgba(54, 150, 252, 0.08);
}
.btn-add-row:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* ------ Admin patterns (extended for new settings pages) ------ */

.admin-form input[type="color"] {
    padding: 0.25rem;
    cursor: pointer;
}
.admin-form-compact { padding: 0.75rem 0; border-bottom: 1px solid var(--border); margin-bottom: 1rem; }
/* Surface inherited from the :is() block in main.css. */
.admin-form-card { padding: 1.25rem 1.5rem; }
.admin-form-success {
    color: var(--success);
    background: rgba(16, 185, 129, 0.08);
    padding: 0.5rem 0.85rem;
    border-radius: var(--radius);
    display: inline-block;
}

.admin-checkbox-row {
    display: flex; align-items: center; gap: 0.55rem;
    padding: 0.35rem 0;
    font-size: 0.9rem;
    cursor: pointer;
}
.admin-checkbox-row input[type="checkbox"] { flex: 0 0 auto; }
.admin-checkbox-row.compact { padding: 0.2rem 0; font-size: 0.85rem; }
.admin-checkbox-row .admin-checkbox-body {
    display: flex; flex-direction: column; gap: 0.15rem;
}
.admin-checkbox-row .admin-checkbox-body code {
    font-size: 0.72rem;
}

.admin-checkbox-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 0.15rem 0.75rem;
    padding: 0.5rem 0;
}
.admin-checkbox-grid.compact {
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 0.1rem 0.5rem;
    max-height: 200px; overflow-y: auto;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 0.5rem;
}

.admin-filters {
    display: flex; gap: 0.5rem; flex: 1 1 auto;
    align-items: center;
}
.admin-filters input[type="search"] {
    flex: 1 1 200px;
    height: 36px;
    padding: 0 0.7rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    font-size: 0.9rem;
}
.admin-filters select {
    height: 36px;
    padding: 0 0.7rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    font-size: 0.9rem;
}

.admin-pager {
    display: flex; align-items: center; justify-content: center; gap: 1rem;
    padding: 0.75rem 0;
    font-size: 0.85rem;
}
.admin-pager:empty { display: none; }

.admin-info-card {
    padding: 1.25rem;
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: var(--surface);
    max-width: 640px;
}
.admin-info-card h3 { margin: 0 0 0.5rem; font-size: 1.1rem; }

/* Page head with inline actions (department selector on helpdesk settings) */
.page-head.page-head-with-actions {
    display: flex; justify-content: space-between; align-items: center;
    flex-wrap: wrap; gap: 0.75rem;
}
.page-head-actions {
    display: flex; align-items: center; gap: 0.5rem;
}

/* Badges */
.badge-o365 {
    padding: 0 0.4rem;
    color: var(--ms-blue);
    font-size: 0.85rem;
}

/* Role detail drawer */
.role-detail h3.role-section-title,
.admin-form h3.role-section-title {
    font-size: 0.95rem; font-weight: 600; color: var(--fg);
    margin: 1.25rem 0 0.35rem; padding-bottom: 0.25rem;
    border-bottom: 1px solid var(--border);
}

/* Team grouping on /agent/settings/departments/{id}/team — one section per
   team. Header has an underline that visually separates each team-block. */
.team-group { margin-bottom: 2rem; }
.team-group:last-child { margin-bottom: 0; }
.team-group-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    margin-bottom: 0.6rem;
    padding-bottom: 0.4rem;
    border-bottom: 1px solid var(--border);
}
.team-group-title {
    font-size: 1.1rem;
    font-weight: 600;
    color: var(--fg);
    margin: 0;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex: 1 1 auto;
    min-width: 0;
}
.team-group-title i { color: var(--muted); font-size: 0.95rem; }
.team-group-count {
    background: var(--shade-2);
    color: var(--muted);
    font-size: 0.72rem;
    font-weight: 600;
    padding: 0.1rem 0.5rem;
    border-radius: 999px;
}
.team-group-actions {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    flex-shrink: 0;
}
.team-group-empty { margin: 0.4rem 0.25rem; font-size: 0.88rem; }

/* Push a button to the leading edge of its container while siblings
   stay at the trailing edge. Generic — used by both .admin-form-actions
   (e.g. "Remove technician" left of Save/Cancel) and .log-filter-actions
   (e.g. "Eksporter til Excel" left of Filter/Reset). */
.form-action-leading { margin-right: auto; }

/* Spread variant of .log-filter-actions: stretch to fill the grid cell
   so buttons can split across the full width via .form-action-leading. */
.log-filter-actions.log-filter-actions-spread {
    justify-self: stretch;
    width: 100%;
}

/* Compact user-summary in technician-edit modal (avatar + name + mail).
   Stays compact on its own — does NOT use .admin-head because that leaks
   `.admin-head .muted { flex: 1 1 280px }` into the column-flex mail-line
   and blows the block up to ~280px tall. */
.user-summary {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 0.75rem;
}
.user-summary-text { display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; }
.user-summary strong { font-size: 1rem; }
.user-summary .user-mail { font-size: 0.85rem; flex: none; }
/* Bordered variant — used when the user-summary REPLACES a form field
   (e.g. after picking a user in the "Ny tekniker" modal). The "Bytt"
   button sits on the trailing edge to restore the picker. */
.user-summary-bordered {
    padding: 0.5rem 0.75rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
}
.user-summary-bordered .btn-sm { margin-left: auto; flex-shrink: 0; }

/* Tab-count badge in settings-tabs (e.g. "Tilganger 12" / "Brukere 3") */
.settings-tab .tab-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.4rem;
    padding: 0 0.4rem;
    margin-left: 0.4rem;
    background: var(--shade-2);
    color: var(--muted);
    border-radius: 999px;
    font-size: 0.72rem;
    font-weight: 600;
}
.settings-tab.active .tab-count {
    background: var(--icon-blue-soft);
    color: var(--accent);
}

/* "Slå opp bruker" drawer on /agent/settings/access — shows the user's
   roles for cleanup. Header (avatar + name) + role list where each
   row is a `.surface .user-lookup-role` with title/scope, access codes
   and a remove button. Privileged roles (super_admin/access_manage) have
   a shield icon instead of a cross — H3-safeguard. */
.user-lookup-empty {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 1rem;
    background: var(--shade-1);
    border-radius: var(--radius);
}
.user-lookup-header {
    display: grid;
    grid-template-columns: auto 1fr auto;
    gap: 0.9rem;
    align-items: center;
    padding: 0.9rem 0.4rem 1rem;
}
.user-lookup-avatar { display: flex; }
.user-lookup-meta { display: flex; flex-direction: column; gap: 0.15rem; }
.user-lookup-count { font-size: 0.85rem; }
.user-lookup-roles {
    margin: 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}
.user-lookup-role {
    display: grid;
    grid-template-columns: 1fr auto;
    grid-template-areas:
        "toggle actions"
        "access access";
    gap: 0 0.4rem;
    padding: 0;
    align-items: stretch;
    overflow: hidden;
}
.user-lookup-role-toggle {
    grid-area: toggle;
    display: flex;
    align-items: center;
    gap: 0.6rem;
    flex-wrap: wrap;
    padding: 0.7rem 0.4rem 0.7rem 0.85rem;
    background: transparent;
    border: 0;
    color: var(--fg);
    font: inherit;
    text-align: left;
    cursor: pointer;
    transition: background 0.12s;
}
.user-lookup-role-toggle:hover { background: var(--shade-1); }
.user-lookup-role-toggle:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: -2px;
}
.user-lookup-role-chevron {
    color: var(--muted);
    transition: transform 0.15s ease;
    flex: 0 0 auto;
}
.user-lookup-role.is-expanded .user-lookup-role-chevron {
    transform: rotate(90deg);
}
.user-lookup-role-count {
    font-size: 0.82rem;
    margin-left: auto;
}
.user-lookup-role-access {
    grid-area: access;
    display: flex;
    flex-wrap: wrap;
    gap: 0.3rem;
    padding: 0 0.85rem 0.7rem;
    font-size: 0.85rem;
    border-top: 1px solid var(--border);
    padding-top: 0.6rem;
}
.user-lookup-role-access code {
    font-size: 0.78rem;
    padding: 0.08em 0.45em;
}
.user-lookup-role-actions {
    grid-area: actions;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    padding: 0.4rem 0.55rem;
}
.user-lookup-shield {
    color: var(--icon-amber);
    font-size: 0.95rem;
    padding: 0 0.2rem;
    cursor: help;
    flex: 0 0 auto;
}

/* Toggle-switch for access permissions — erstatter checkbox-row i role-drawer */
.access-toggle-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 0.1rem;
    margin: 0.5rem 0;
}
@media (min-width: 540px) {
    .access-toggle-grid { grid-template-columns: 1fr 1fr; gap: 0.1rem 1rem; }
}
.access-toggle {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    padding: 0.55rem 0.65rem;
    cursor: pointer;
    border-radius: var(--radius);
    transition: background 0.12s;
    user-select: none;
}
.access-toggle:hover { background: var(--shade-1); }
.access-toggle input[type="checkbox"] {
    position: absolute;
    width: 1px; height: 1px;
    opacity: 0;
    pointer-events: none;
}
.access-toggle .toggle-switch {
    position: relative;
    width: 32px;
    height: 18px;
    background: var(--border-strong, var(--border));
    border-radius: 999px;
    transition: background 0.15s;
    flex-shrink: 0;
}
.access-toggle .toggle-switch::after {
    content: "";
    position: absolute;
    top: 2px; left: 2px;
    width: 14px; height: 14px;
    background: var(--surface);
    border-radius: 50%;
    transition: transform 0.15s;
    box-shadow: var(--shadow-sm);
}
.access-toggle input:checked + .toggle-switch { background: var(--accent); }
.access-toggle input:checked + .toggle-switch::after { transform: translateX(14px); }
.access-toggle input:focus-visible + .toggle-switch {
    outline: 2px solid rgba(54, 150, 252, 0.4);
    outline-offset: 2px;
}
.access-toggle-label {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 0.9rem;
    color: var(--fg);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Tight grouping for related toggles in a form (e.g. three feature-flags
   inside an edit-modal). The wrapper counts as one .admin-form child so
   the group gets the form's normal 1rem gap from neighbours; inside the
   group, individual toggles stack with reduced vertical padding so they
   read as one cluster. */
.toggle-group {
    display: flex;
    flex-direction: column;
}
.toggle-group .access-toggle {
    padding-top: 0.25rem;
    padding-bottom: 0.25rem;
}

/* Email in list-item-secondary should break otherwise — let the badge-row
   shrink the me-span instead of overflowing the drawer. */
.role-detail .user-mail {
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
}

/* Token result (one-time display) */
.token-result-box {
    margin: 0.75rem 0;
    padding: 0.85rem;
    border: 1px solid var(--icon-amber);
    border-radius: var(--radius);
    background: var(--icon-amber-soft);
}
.token-value {
    font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
    font-size: 0.78rem;
    padding: 0.5rem;
    background: var(--code-bg);
    color: var(--code-fg);
    border-radius: var(--radius);
    overflow-x: auto;
    word-break: break-all;
    white-space: pre-wrap;
}
.settings-managers-drawer { display: flex; flex-direction: column; gap: 0.75rem; }

/* Section title inside a tab panel */
.settings-section-title {
    font-size: 1rem; font-weight: 600;
    margin: 1.5rem 0 0.5rem;
    padding-bottom: 0.25rem;
    border-bottom: 1px solid var(--border);
}

/* Messaging status card — top of /agent/settings/mail.
   Mode-colored left-border signals at a glance whether outbound is live,
   dry-run (debug) or observe (shared DB).
   Surface-tokens inherited from the :is() block in main.css; only structure
   here + the colored category-marker border edge. */
.messaging-status-card {
    border-left: 4px solid var(--icon-blue);
    padding: 1rem 1.15rem;
    margin-bottom: 1.25rem;
}
.messaging-status-card.is-live    { border-left-color: var(--icon-red);    background: var(--icon-red-soft); }
.messaging-status-card.is-dev     { border-left-color: var(--icon-green);  background: var(--icon-green-soft); }
.messaging-status-card.is-observe { border-left-color: var(--icon-purple); background: var(--icon-purple-soft); }
.messaging-status-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    margin-bottom: 0.5rem;
}
.messaging-status-head > div { display: flex; align-items: center; gap: 0.6rem; }
.messaging-status-badge {
    display: inline-flex;
    align-items: center;
    padding: 0.2rem 0.55rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 999px;
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--fg);
}
.messaging-status-title { color: var(--fg); font-size: 1rem; }
.messaging-status-desc  { margin: 0; color: var(--fg); font-size: 0.92rem; line-height: 1.45; }
.messaging-status-card hr {
    border: 0;
    border-top: 1px solid var(--border);
    margin: 0.85rem 0;
}
.messaging-status-inbound { margin: 0; font-size: 0.88rem; }
.messaging-mode-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 0.6rem;
    margin-top: 1rem;
}
.mode-btn {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.25rem;
    padding: 0.7rem 0.85rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    color: var(--fg);
    cursor: pointer;
    text-align: left;
    transition: border-color 0.12s, box-shadow 0.12s, transform 0.12s;
}
.mode-btn:hover {
    border-color: var(--accent);
    box-shadow: var(--shadow-sm);
    transform: translateY(-1px);
}
.mode-btn.is-active {
    border-color: var(--accent);
    background: var(--icon-blue-soft);
    cursor: default;
}
.mode-btn.is-active:hover { transform: none; }
.mode-btn i {
    font-size: 1rem;
    color: var(--muted);
}
.mode-btn.is-active i { color: var(--accent); }
.mode-btn.mode-live.is-active i    { color: var(--icon-red); }
.mode-btn.mode-dev.is-active i     { color: var(--icon-green); }
.mode-btn.mode-observe.is-active i { color: var(--icon-purple); }
.mode-btn-label {
    font-size: 0.88rem;
    font-weight: 600;
}
.mode-btn-desc {
    font-size: 0.75rem;
    line-height: 1.35;
}

/* ------ Detail layout (reusable) ------
   Side-by-side: full-height sidebar (viewport-sticky from topbar bottom)
   + main content that flows naturally with its own background and does
   not have its own scrollbar. Hosted inside agent-frame main#app but drops
   the default max-width + padding so the sidebar sits *against*
   agent-sidebar (no gap).

   Sticky sidebar instead of flex-stretch: main content is often short
   (form with 4 fields) — then it's meaningless to force the WHOLE layout
   to 100vh. The sidebar gets its own viewport-sticky full height while
   main flows naturally and inherits body background.

   See docs/components/detail-layout.md. */

/* Must have higher specificity than the `.agent-frame > main#app` rule
   (which sets max-width + padding). Use the same chain to win. */
.agent-frame > main#app.detail-layout-host {
    max-width: none;
    padding: 0;
    margin: 0;
    width: 100%;
    background: transparent;
}
.detail-layout {
    display: flex;
    align-items: flex-start;
    /* no separate background — inherits body background so main looks the
       same as the rest of the app. The sidebar has its own surface background. */
}
/* Sidebar collapse — toggled from the page-toolbar's sidebar button. Hides
   the entire left column so the main content (asset grid, etc.) gets the
   whole width. The resize-handle goes with it. */
.detail-layout.is-sidebar-hidden > .detail-sidebar { display: none; }
.detail-sidebar {
    flex: 0 0 var(--detail-sidebar-width, 260px);
    width: var(--detail-sidebar-width, 260px);
    background: var(--surface);
    border-right: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    min-width: 0;
    /* Sticky so the sidebar keeps full height regardless of main height.
       The topbar is 64px above #app, so `top: 0` inside #app is exactly
       below the topbar. */
    position: sticky;
    top: 0;
    height: calc(100vh - var(--agent-topbar-height));
    z-index: 1;
}
.detail-sidebar-head {
    padding: 1rem 1.25rem 0.85rem;
    border-bottom: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
}
.detail-sidebar-head .back-link { font-size: 0.85rem; }
.detail-sidebar-title {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    font-size: 1.05rem;
    min-width: 0;
}
.detail-sidebar-title-icon i { font-size: 1.2rem; color: var(--muted); }
.detail-sidebar-title-text {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    min-width: 0;
    overflow: hidden;
}
.detail-sidebar-title-text strong {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--fg);
}
.detail-sidebar-title-text .muted { font-size: 0.78rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.detail-sidebar-nav {
    flex: 1 1 auto;
    overflow-y: auto;
    padding: 0.5rem 0.4rem;
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
}
.detail-sidebar-item {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.55rem 0.85rem;
    color: var(--muted);
    text-decoration: none;
    font-size: 0.95rem;
    border-radius: var(--radius);
    border-left: 3px solid transparent;
}
.detail-sidebar-item:hover { background: var(--shade-1); color: var(--fg); }
.detail-sidebar-item.active {
    color: var(--accent);
    background: var(--icon-blue-soft);
    border-left-color: var(--accent);
    font-weight: 500;
}
.detail-sidebar-item i { width: 1.2em; text-align: center; color: var(--muted); }
.detail-sidebar-item:hover i { color: var(--accent); }
.detail-sidebar-item.active i { color: var(--accent); }

/* Drag-handle on the right edge of the sidebar. 6px hit-zone, 1px visual line. */
.detail-sidebar-resize {
    position: absolute;
    top: 0;
    right: -3px;
    bottom: 0;
    width: 6px;
    cursor: col-resize;
    z-index: 2;
}
.detail-sidebar-resize::after {
    content: '';
    position: absolute;
    top: 0; bottom: 0;
    left: 50%;
    width: 1px;
    background: transparent;
    transition: background 0.12s;
}
.detail-sidebar-resize:hover::after,
body.is-resizing .detail-sidebar-resize::after { background: var(--accent); }

.detail-main {
    flex: 1 1 auto;
    min-width: 0;
    /* No overflow-y: auto — main flows naturally. If content is short
       there's no scrollbar to look at. The page scrolls via
       document-level scroll just like the rest of the app. */
    padding: 1.5rem 1.75rem;
    /* No separate background — inherits body background. */
}

@media (max-width: 780px) {
    /* Mobile: stack sidebar above main, full-width, drop height-lock.
       Drag-handle is hidden. */
    .detail-layout {
        display: block;
        height: auto;
    }
    .detail-sidebar {
        width: 100% !important;
        flex: none;
        border-right: 0;
        border-bottom: 1px solid var(--border);
    }
    .detail-sidebar-resize { display: none; }
    .detail-main { padding: 1rem 1rem 2rem; }
}

/* ----- CMDB landing + filter ----- */

/* Stat-tile colour variants. Same saturated 2-colour gradient look as
   the original .stat-mine/.stat-pending/etc (removed 2026-05-14), but
   class names now match the design-system colour tokens (blue/green/
   amber/red/purple) so they can be reused across dashboards instead of
   being helpdesk-domain-specific. Gradient endpoints live as tokens
   (--stat-X-from/-to) in main.css :root. Both dashboards (agent +
   CMDB) use these. */
.stat-token.stat-red    { background: linear-gradient(135deg, var(--stat-red-from)    0%, var(--stat-red-to)    100%); }
.stat-token.stat-amber  { background: linear-gradient(135deg, var(--stat-amber-from)  0%, var(--stat-amber-to)  100%); }
.stat-token.stat-purple { background: linear-gradient(135deg, var(--stat-purple-from) 0%, var(--stat-purple-to) 100%); }
.stat-token.stat-green  { background: linear-gradient(135deg, var(--stat-green-from)  0%, var(--stat-green-to)  100%); }
.stat-token.stat-blue   { background: linear-gradient(135deg, var(--stat-blue-from)   0%, var(--stat-blue-to)   100%); }

/* Disabled stat-tile (Phase 2 placeholders) — per design.md
   §Hover-affordance: non-clickable elements must not hover-lift. */
.cmdb-stat-disabled { opacity: 0.55; cursor: default; }
.cmdb-stat-disabled:hover { transform: none; }

/* Textual stat value (e.g. "5 min siden") needs a smaller font than
   .agent-stat-number's default 2rem. */
.cmdb-stat-text { font-size: 1.1rem; font-weight: 600; }

/* Chart-card placeholders — empty canvas replaced with a centred
   icon+text stub until sync populates the relevant columns. */
.cmdb-chart-placeholder { min-height: 220px; }
.cmdb-chart-stub {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    padding: 1.5rem 1rem;
    text-align: center;
    min-height: 160px;
}
.cmdb-chart-stub i { font-size: 2.25rem; color: var(--muted); }
.cmdb-chart-stub p { margin: 0; max-width: 26ch; }

/* Sidebar — gap between action-tiles and recent-card. */
.cmdb-aside { gap: 1rem; }

/* Recent list in the sidebar — tighter than .list-item since it lives
   inside a .card and rows are not clickable. */
.cmdb-aside-recent { padding: 1rem 1.25rem 1.25rem; }
.cmdb-aside-recent .section-head { margin-bottom: 0.75rem; }
.cmdb-aside-recent .section-head h3 { font-size: 0.95rem; margin: 0; }
.cmdb-aside-list { display: flex; flex-direction: column; gap: 0.55rem; }
.cmdb-aside-list-item { display: flex; flex-direction: column; gap: 0.1rem; }
.cmdb-aside-list-name {
    font-size: 0.9rem;
    font-weight: 500;
    color: var(--fg);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.cmdb-aside-list-meta {
    font-size: 0.78rem;
    font-variant-numeric: tabular-nums;
}

/* Filter page: head-row above the results. */
.cmdb-filter-form { padding: 1rem 1.25rem 1.25rem; }

/* Multi-select host inside the filter form — chip-multi-select renders its
   own .ff-multi wrapper, this is just the slot we drop it into. */
.cmdb-filter-multi-host > .ff-multi {
    margin: 0;
}

/* Placeholder field — visible for CMDB parity but disabled until Phase 2
   sync extends the data we have. Mimics an input-style box but greyed,
   with a clock-icon hint that this is "coming soon". */
.cmdb-filter-placeholder-field {
    opacity: 0.7;
}
.cmdb-filter-placeholder {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    height: 38px;
    padding: 0 0.7rem;
    border: 1px dashed var(--border-strong);
    border-radius: var(--radius);
    background: var(--shade-1);
    color: var(--muted);
    font-size: 0.85rem;
    cursor: not-allowed;
}
.cmdb-filter-placeholder i { color: var(--icon-amber); }

/* ----- Asset card grid (filter results) ----- */
/* auto-FILL (not auto-FIT) keeps empty tracks instead of collapsing them —
   a single card stays at its track size instead of stretching to the full
   row. `1fr` as the max lets each track grow to fill available width when
   multiple cards are present, so the row actually fills horizontally
   instead of leaving whitespace on the right. Track count adapts:
     * narrow main (sidebar visible)      → 2 tracks at ~450px
     * wider main (sidebar hidden)        → 3 tracks at ~390px
     * very wide                          → 4+ tracks
   300px min keeps cards readable; below 600px we collapse to a single
   full-width column via the media query below. */
.cmdb-asset-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    gap: 1rem;
}
/* On narrow viewports the filter sidebar is already hidden by detail-
   layout's mobile stack, so the grid gets the whole width. Force single
   column at the cards' min-width threshold so we don't end up with one
   340px card on a 360px screen leaving 20px of whitespace. */
@media (max-width: 600px) {
    .cmdb-asset-grid {
        grid-template-columns: 1fr;
    }
}

/* Two-column layout inside each card: icon | body. Icon spans the full
   vertical of the card (it's an image at scale-up, FA-icon as fallback);
   body stacks name → subtitle → owner → footer with badges + mini-icons. */
.cmdb-asset-card {
    /* Surface tokens come from .surface in markup. Structure only here. */
    display: grid;
    grid-template-columns: 60px 1fr;
    gap: 0.9rem;
    padding: 0.9rem 1rem;
    color: var(--fg);
    text-decoration: none;
    min-height: 120px;
}
a.cmdb-asset-card { cursor: pointer; transition: transform .08s ease, box-shadow .12s ease; }
a.cmdb-asset-card:hover { transform: translateY(-1px); box-shadow: var(--shadow-sm, 0 1px 3px rgba(0,0,0,.08)); }

.cmdb-asset-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 60px;
    height: 60px;
    border-radius: var(--radius);
    background: var(--shade-2);
    color: var(--muted);
    font-size: 1.4rem;
    overflow: hidden;
    align-self: start;
}
.cmdb-asset-icon-img {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}
/* Brand-image fallback (used when there's no model image) needs some inset
   so a square logo doesn't touch the rounded container edges. */
.cmdb-asset-icon-img-pad {
    max-width: 80%;
    max-height: 80%;
}

.cmdb-asset-body {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    min-width: 0;
}
.cmdb-asset-name {
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--fg);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.cmdb-asset-subtitle {
    font-size: 0.85rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.cmdb-asset-owner {
    margin: 0.05rem 0 0;
    font-size: 0.85rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.cmdb-asset-card-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    margin-top: auto;            /* pushes badges to the bottom of the card */
    padding-top: 0.4rem;
}
.cmdb-asset-badges {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem;
    min-width: 0;
}
.cmdb-asset-mini-icons {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    flex-shrink: 0;
}
.cmdb-asset-mini-icon,
.cmdb-asset-mini-icon-fa,
.cmdb-asset-mini-flag {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    font-size: 0.95rem;
}
.cmdb-asset-mini-icon { border-radius: 50%; object-fit: contain; }
.cmdb-asset-mini-icon-fa { color: var(--muted); }
.cmdb-asset-mini-flag { color: var(--icon-red); }
/* Model-age warning uses amber, not red — distinguishes "old hardware
   (replace soon)" from "OS end-of-life (security risk)". */
.cmdb-asset-mini-flag-amber { color: var(--icon-amber); }
.cmdb-asset-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.15rem 0.55rem;
    border-radius: 999px;
    background: var(--icon-blue-soft);
    color: var(--icon-blue);
    font-size: 0.75rem;
    font-weight: 500;
}
/* Colour variants. Driven by `cmdb-format.js` (sourceInfo / stateVariant /
   statusVariant) — frontends should never pick a colour token directly,
   only the variant name. New variants? Add the mapping in cmdb-format.js
   AND the CSS class here. */
.cmdb-asset-badge-blue   { background: var(--icon-blue-soft);   color: var(--icon-blue);   }
.cmdb-asset-badge-green  { background: var(--icon-green-soft);  color: var(--icon-green);  }
.cmdb-asset-badge-amber  { background: var(--icon-amber-soft);  color: var(--icon-amber);  }
.cmdb-asset-badge-red    { background: var(--icon-red-soft);    color: var(--icon-red);    }
.cmdb-asset-badge-muted  { background: var(--shade-2);          color: var(--muted);       }
/* Legacy aliases — pre-2026-05-15 state badge always rendered green and
   warn always red. Kept until call-sites migrate to the variant API. */
.cmdb-asset-badge-state {
    background: var(--icon-green-soft);
    color: var(--icon-green);
}
.cmdb-asset-icon-flag {
    color: var(--icon-red);
    font-size: 0.95rem;
}

/* ----- Asset detail page (/agent/cmdb/{id}) ----- */
/* Mirrors CMDB's /asset/:id: a full-width device header card,
   then a 3-column row (Location/Organization/Owner), then a
   2-column row (History/Tekniske detaljer). Cards use .surface
   for token-aligned background/border. */
.cmdb-detail-head {
    display: grid;
    grid-template-columns: auto 1fr minmax(220px, 320px);
    gap: 1.2rem;
    align-items: start;
    padding: 1.1rem 1.3rem;
    margin-bottom: 1rem;
}
.cmdb-detail-head-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 64px;
    height: 64px;
    border-radius: 14px;
    background: var(--shade-2);
    color: var(--muted);
    font-size: 1.6rem;
    flex-shrink: 0;
    overflow: hidden;
}
/* The asset image inside the head — same shape as the filter-card icon
   but bigger. `object-fit: contain` keeps brand logos from being squashed
   and lets the placeholder SVG sit cleanly centered. */
.cmdb-detail-head-icon-img {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}
/* OS-icon prefix in the head meta-list — same colour as the FA brand
   glyph it represents (Windows blue, Apple grey, Linux orange) so the
   text next to it doesn't pretend to be a link. */
.cmdb-detail-os-icon {
    color: var(--muted);
    margin-right: 0.2rem;
}

/* ----- JSON tree (used by asset-detail Ext. dataset) ----- */
/* The component (`components/json-tree.js`) owns the markup; this only
   styles it. Visual goal: dense but readable, with primitives mostly
   plain-text and toggles dim until hovered. Toggle button looks like a
   text token, not a chunky button, so the tree feels like inspectable
   raw data rather than a UI control. */
.json-tree {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.82rem;
    line-height: 1.55;
    color: var(--fg);
}
.json-tree-list {
    list-style: none;
    padding: 0;
    margin: 0;
}
.json-tree-list .json-tree-list {
    /* Indent nested layers. 1.25rem ≈ tab-stop without being huge. */
    padding-left: 1.25rem;
    border-left: 1px dashed var(--border);
    margin: 0.15rem 0 0.25rem;
}
/* Nested lists collapse by default; the toggle handler flips this. */
.json-tree-nested { display: none; }
.json-tree-nested.is-open { display: block; }

.json-tree-key {
    color: var(--fg);
    font-weight: 600;
}
.json-tree-value { color: var(--accent); }
.json-tree-null { color: var(--muted); font-style: italic; }
.json-tree-bool { color: var(--icon-amber); font-weight: 500; }

.json-tree-hint {
    color: var(--muted);
    font-size: 0.78rem;
}
.json-tree-toggle {
    background: transparent;
    border: 0;
    padding: 0 0.2rem;
    font: inherit;
    color: var(--accent);
    cursor: pointer;
}
.json-tree-toggle:hover,
.json-tree-toggle:focus-visible {
    color: var(--link-hover);
    outline: 0;
}
.json-tree-toggle:focus-visible { text-decoration: underline; }
/* Wraps the image when it's clickable (lightbox trigger). Fills the
   parent's 64x64 box; no own border / background — the parent
   `.cmdb-detail-head-icon` already paints the surface. Subtle scale on
   hover so the user discovers "this is clickable". */
.cmdb-detail-head-icon-button {
    width: 100%;
    height: 100%;
    padding: 0;
    background: transparent;
    border: 0;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    transition: transform 0.12s ease;
}
.cmdb-detail-head-icon-button:hover,
.cmdb-detail-head-icon-button:focus-visible {
    transform: scale(1.04);
    outline: 0;
}
.cmdb-detail-head-icon-button:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}
.cmdb-detail-head-body { min-width: 0; }
.cmdb-detail-name {
    margin: 0 0 0.2rem;
    font-size: 1.3rem;
    font-weight: 600;
    color: var(--fg);
}
.cmdb-detail-description {
    margin: 0 0 0.35rem;
    font-size: 0.92rem;
    color: var(--fg);
}
.cmdb-detail-subtitle {
    margin: 0 0 0.5rem;
    font-size: 0.85rem;
}
/* Free-form notes under the device header. CMDB stores `devices.notes`
   as multi-line text — preserve linebreaks. Italic-muted when empty so
   the slot is visible but obviously a placeholder. */
.cmdb-detail-notes {
    margin: 0.25rem 0 0.6rem;
    font-size: 0.9rem;
    white-space: pre-wrap;
    word-break: break-word;
}
.cmdb-detail-notes-empty {
    font-style: italic;
}
/* Tags strip under the notes. Read-only pills with the muted-soft look
   from CMDB (Phase 2 will add an `<button class="chip-remove">` + an
   "+Add tag"-trigger; until then the strip is informational only). */
.cmdb-detail-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
    margin: 0.25rem 0 0.6rem;
}
.cmdb-detail-tag {
    display: inline-flex;
    align-items: center;
    padding: 0.15rem 0.6rem;
    background: var(--shade-2);
    color: var(--fg);
    border-radius: 999px;
    font-size: 0.78rem;
    font-weight: 500;
}
/* ----- Users data-integrity report (/agent/settings/users/integrity) ----- */
/* Three vertically-stacked sections (blocking / warnings / fk-inventory),
   each containing a list of <details> categories. Categories with
   findings auto-expand; empty ones stay collapsed. */
.integrity-intro { margin: 0 0 1.25rem; max-width: 760px; }
.integrity-section { margin-bottom: 2rem; }
.integrity-section h2 {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    font-size: 1rem;
    margin: 0 0 0.75rem;
    padding-bottom: 0.4rem;
    border-bottom: 1px solid var(--border);
}
.integrity-section-blocking h2 i { color: var(--icon-red); }
.integrity-section-warnings h2 i { color: var(--icon-amber); }
.integrity-section-fk-inventory h2 i { color: var(--muted); }

.integrity-category {
    margin: 0.5rem 0;
    padding: 0.65rem 0.85rem;
    background: var(--shade-1);
    border-radius: var(--radius);
}
.integrity-category[open] { background: var(--surface); border: 1px solid var(--border); }
.integrity-category > summary {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    cursor: pointer;
    font-weight: 500;
    list-style: none;
}
.integrity-category > summary::-webkit-details-marker { display: none; }
.integrity-category > summary::before {
    content: '▸';
    color: var(--muted);
    transition: transform 0.12s ease;
}
.integrity-category[open] > summary::before { transform: rotate(90deg); }
.integrity-category-title { flex: 1; }
.integrity-category-count { font-size: 0.82rem; }
.integrity-category-empty { margin: 0.5rem 0 0; }
.integrity-category-hint {
    margin: 0.5rem 0 0.75rem;
    font-size: 0.85rem;
    line-height: 1.5;
}
.integrity-category-hint code {
    background: var(--shade-2);
    padding: 0.05em 0.3em;
    border-radius: 3px;
    font-size: 0.9em;
}

.integrity-group {
    margin: 0.75rem 0;
    padding: 0.75rem 0.85rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
}
.integrity-group-head {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    margin-bottom: 0.5rem;
}
.integrity-group-actions {
    margin-top: 0.6rem;
    display: flex;
    justify-content: flex-end;
}

.integrity-user-list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
}
.integrity-user-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.4rem 0.55rem;
    background: var(--shade-1);
    border-radius: var(--radius);
    font-size: 0.85rem;
}
.integrity-user-pick { display: flex; align-items: center; }
.integrity-user-cells {
    flex: 1;
    display: grid;
    grid-template-columns: 60px minmax(140px, 1.5fr) minmax(180px, 2fr) auto minmax(180px, 2fr) 110px;
    gap: 0.5rem;
    align-items: baseline;
    min-width: 0;
}
.integrity-user-activity {
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.integrity-user-cells > div {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.integrity-user-name { font-weight: 500; }

.integrity-fk-inventory {
    margin-top: 0.5rem;
    padding: 0.65rem 0.85rem;
    background: var(--shade-1);
    border-radius: var(--radius);
}
.integrity-fk-inventory[open] { background: var(--surface); border: 1px solid var(--border); }
.integrity-fk-inventory > summary {
    cursor: pointer;
    font-weight: 500;
}
.integrity-fk-table {
    width: 100%;
    margin-top: 0.6rem;
    border-collapse: collapse;
    font-size: 0.82rem;
}
.integrity-fk-table th,
.integrity-fk-table td {
    padding: 0.4rem 0.6rem;
    text-align: left;
    border-bottom: 1px solid var(--border);
}
.integrity-fk-table th { color: var(--muted); font-weight: 500; }
.integrity-fk-table code {
    background: var(--shade-2);
    padding: 0.05em 0.3em;
    border-radius: 3px;
}

/* Merge modal step 1 + step 2 inside the same modal body */
.merge-modal-step { font-size: 0.9rem; line-height: 1.55; }
.merge-modal-users { list-style: none; padding: 0; margin: 0.6rem 0 0; display: flex; flex-direction: column; gap: 0.4rem; }
.merge-modal-user-pick {
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    padding: 0.6rem 0.75rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    cursor: pointer;
}
.merge-modal-user-pick:has(input:checked) {
    border-color: var(--accent);
    background: var(--icon-blue-soft);
}
.merge-modal-user-body { display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; }
.merge-modal-user-meta { font-size: 0.78rem; }
.merge-modal-user-line { display: flex; align-items: center; gap: 0.5rem; }
/* Badge marking the auto-picked "most active" suggestion. Green-soft
   to telegraph "good default" without overpowering the actual primary
   picker. */
.merge-modal-user-suggested {
    display: inline-flex;
    align-items: center;
    padding: 0.05rem 0.4rem;
    border-radius: 999px;
    background: var(--icon-green-soft);
    color: var(--icon-green);
    font-size: 0.7rem;
    font-weight: 500;
}
.merge-modal-user-activity {
    font-size: 0.82rem;
    font-variant-numeric: tabular-nums;
}
.merge-modal-step-2 hr { margin: 1rem 0; border: 0; border-top: 1px solid var(--border); }
.merge-modal-actions { display: flex; gap: 0.5rem; justify-content: flex-end; margin-top: 1rem; }

/* Inline action-link in the History card header ("Opprett sak"). Sits
   to the right of the title via the `.cmdb-detail-card h2 { display:flex }`
   rule above, accent-coloured so it reads as a primary action. */
.cmdb-history-action {
    margin-left: auto;
    font-size: 0.82rem;
    font-weight: 500;
    color: var(--accent);
    text-decoration: none;
}
.cmdb-history-action:hover { text-decoration: underline; }
/* Merged history timeline — one item per time-event / note / ticket.
   Items stack vertically with a clock-style icon on the left, datetime
   muted-grey, and content (label / note text / ticket link) following.
   No external timeline bar — keeping it dense like CMDB does. */
.cmdb-history-list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 0.85rem;
}
.cmdb-history-item {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 0.15rem 0.65rem;
    align-items: baseline;
    font-size: 0.9rem;
}
.cmdb-history-icon {
    color: var(--muted);
    font-size: 0.95rem;
    grid-row: span 2;
    align-self: start;
    padding-top: 0.1rem;
}
.cmdb-history-time {
    font-size: 0.78rem;
    grid-column: 2;
}
.cmdb-history-label,
.cmdb-history-link {
    grid-column: 2;
    font-weight: 600;
}
.cmdb-history-link {
    color: var(--accent);
    text-decoration: none;
}
.cmdb-history-link:hover { text-decoration: underline; }
.cmdb-history-body {
    grid-column: 2;
    margin: 0;
    white-space: pre-wrap;
    word-break: break-word;
    font-weight: 400;
}
.cmdb-history-byline {
    grid-column: 2;
    font-size: 0.78rem;
}
.cmdb-history-item-ticket .status-pill {
    grid-column: 2;
    width: max-content;
    margin-top: 0.2rem;
}
/* Leaflet map container in the Location card. Fixed height; Leaflet
   handles its own sizing internally once the script initialises. The
   border-radius clips the rounded card corners since tiles otherwise
   square off the bottom. */
.cmdb-detail-map {
    height: 240px;
    margin-top: 0.5rem;
    border-radius: var(--radius);
    overflow: hidden;
    background: var(--shade-1);
}
.cmdb-detail-map-source {
    margin-top: 0.35rem;
    font-size: 0.78rem;
}
/* Fallback link shown when Leaflet fails to load (CSP / network / vendor
   files missing) — replaces the map content with a centred "Vis i OSM"-
   link so users still get a way to see the location. */
.cmdb-detail-map-fallback {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    height: 100%;
    color: var(--accent);
    text-decoration: none;
    font-size: 0.88rem;
}
.cmdb-detail-map-fallback:hover { text-decoration: underline; }
/* Override Leaflet's z-index defaults — its tile-pane is z-index 400
   which would otherwise float above app modals/drawers. Confine the
   map's stacking context to its host. */
.cmdb-detail-map .leaflet-pane,
.cmdb-detail-map .leaflet-control { z-index: auto; }
/* Ext.dataset card — full-bleed under the History/Details row. Spacing
   from the previous row comes from `.cmdb-detail-two { margin-bottom: 1rem }`
   so we don't need a per-card margin-top here (would double the gap). */
.cmdb-detail-ext-host {
    margin-top: 0.5rem;
    padding: 0.25rem 0;
    /* No internal scrollbars — the card grows with the payload and the
       page scrolls naturally. Two nested scroll bars (page + card) is
       awful UX. Long string values use `word-break: break-word` (see
       .json-tree-value below) so they wrap instead of forcing
       horizontal scroll. */
}
/* Wrap long primitive values so a 200-char string doesn't push a
   horizontal scrollbar on the host. */
.cmdb-detail-ext-host .json-tree-value,
.cmdb-detail-ext-host .json-tree-primitive {
    word-break: break-word;
    white-space: pre-wrap;
}
.cmdb-detail-head-badges {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    align-items: center;
}
.cmdb-asset-badge-warn {
    background: var(--icon-red-soft, rgba(220, 53, 69, 0.12));
    color: var(--icon-red, #c0392b);
}
.cmdb-detail-head-meta {
    border-left: 1px solid var(--border);
    padding-left: 1.1rem;
}
.cmdb-detail-head-meta dl {
    margin: 0;
    display: grid;
    gap: 0.4rem;
    font-size: 0.85rem;
}
.cmdb-detail-head-meta dl > div {
    display: grid;
    grid-template-columns: 90px 1fr;
    gap: 0.5rem;
    align-items: baseline;
}
.cmdb-detail-head-meta dt {
    color: var(--muted);
    font-weight: 500;
}
.cmdb-detail-head-meta dd {
    margin: 0;
    color: var(--fg);
    overflow-wrap: anywhere;
}

.cmdb-detail-three {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 1rem;
    margin-bottom: 1rem;
}
.cmdb-detail-two {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(380px, 1fr));
    gap: 1rem;
    margin-bottom: 1rem;
}
.cmdb-detail-card {
    padding: 1rem 1.1rem;
}
.cmdb-detail-card h2 {
    margin: 0 0 0.6rem;
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--fg);
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    flex-wrap: wrap;
}
/* Muted "hint" tucked next to a card title — e.g. "Rådata fra
   intune_school" on the Ext.dataset card. Lighter weight than the
   title and a touch smaller, so the title still reads as primary. */
.cmdb-detail-card-hint {
    font-size: 0.78rem;
    font-weight: 400;
}
.cmdb-detail-card .section-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.5rem;
    margin-bottom: 0.6rem;
}
.cmdb-detail-card .section-head h2 { margin: 0; }
.cmdb-detail-card p { margin: 0 0 0.3rem; font-size: 0.9rem; }
.cmdb-detail-card p:last-child { margin-bottom: 0; }


.cmdb-detail-tickets {
    margin: 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}
.cmdb-ticket-link {
    display: grid;
    grid-template-columns: auto 1fr auto;
    align-items: center;
    gap: 0.55rem;
    padding: 0.55rem 0.7rem;
    text-decoration: none;
    color: var(--fg);
}
.cmdb-ticket-link:hover { background: var(--shade-1); }
.cmdb-ticket-link .list-item-primary {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: 500;
}
.cmdb-ticket-link .list-item-secondary {
    font-size: 0.82rem;
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    white-space: nowrap;
}

/* Single-column "label: value" stack, matching CMDB's asset-detail
   Details card. Previously this was a 2-col responsive grid which made
   pairs flow into columns — looked busier than the CMDB design and
   created the two-row visual the user flagged. Switched to a flat
   vertical list with label width fixed (so values align), no row
   dividers (each entry stands on its own). */
.cmdb-detail-techlist {
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 0.55rem;
}
.cmdb-detail-techlist > div {
    display: grid;
    grid-template-columns: 120px 1fr;
    gap: 0.65rem;
    align-items: baseline;
    font-size: 0.9rem;
}
.cmdb-detail-techlist dt {
    color: var(--fg);
    font-weight: 600;
}
.cmdb-detail-techlist dt::after {
    content: ':';
    color: var(--muted);
}
.cmdb-detail-techlist dd {
    margin: 0;
    color: var(--fg);
    overflow-wrap: anywhere;
}

/* Collapse head card to a single column on narrow screens. */
@media (max-width: 720px) {
    .cmdb-detail-head {
        grid-template-columns: 1fr;
    }
    .cmdb-detail-head-meta {
        border-left: 0;
        border-top: 1px solid var(--border);
        padding-left: 0;
        padding-top: 0.8rem;
    }
}

/* Utility: non-wrapping cell (used in log-table and data tables). */
.nowrap { white-space: nowrap; }

/* Outbox details (response error message below table row). */
.log-response-row td { background: var(--surface-2); padding: 0.5rem 0.75rem; }
.log-response {
    margin: 0;
    font-family: var(--font-mono, ui-monospace, monospace);
    font-size: 0.82rem;
    white-space: pre-wrap;
    word-break: break-word;
    color: var(--fg);
}

/* Form-fields editor: three-column layout (label / Vis / Obligatorisk).
   Always-on rows (title/description) are tinted + show the "(alltid på)"
   hint; required-not-eligible fields (attachment, critical, confirm)
   keep their required-checkbox locked off. */
.field-toggle-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}
.field-toggle-head,
.field-toggle-row {
    display: grid;
    grid-template-columns: 1fr 5rem 7rem;
    align-items: center;
    column-gap: 0.5rem;
}
.field-toggle-head {
    padding: 0 0.75rem 0.25rem;
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--muted);
}
.field-toggle-col-head { text-align: center; }
.field-toggle-row {
    padding: 0.5rem 0.75rem;
    border: 1px solid var(--border);
    border-radius: var(--radius, 6px);
    background: var(--surface);
}
.field-toggle-row.is-locked { background: var(--shade-1); opacity: 0.85; }
.field-toggle-cell {
    display: flex;
    justify-content: center;
    align-items: center;
    margin: 0;
    cursor: pointer;
}
.field-toggle-cell input:disabled { cursor: not-allowed; }
.field-toggle-text { font-weight: 500; }
.field-toggle-hint { font-size: 0.8rem; }

/* ------ Mail-account unified list (department detail page → Email) ------ */

/* Choice card — generic "pick between alternatives" card, see
   docs/components/choice-card.md. Used in wizard modals (e.g.
   mail-account setup step 1). Don't confuse with .settings-tile
   (navigate to page, has chevron) or .tile (landing view). */
.choice-card-list {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}
.choice-card-intro { margin: 0 0 0.25rem; font-size: 0.88rem; }
.choice-card {
    /* Surface-tokens + hover-lift inherited from the :is() block under
       "CANONICAL ROW-SURFACE" in main.css. Only structure here. */
    display: flex;
    align-items: flex-start;
    gap: 0.9rem;
    width: 100%;
    padding: 0.85rem;
    text-align: left;
    cursor: pointer;
    /* The button element does NOT inherit the fg-token from body — the browser
       default is black, which collides in dark mode. Set explicitly so all
       children inherit the correct theme color (see docs/design.md §Dark mode). */
    color: var(--fg);
    font: inherit;
}
.choice-card.is-recommended {
    border-color: var(--icon-purple);
    background: var(--icon-purple-soft);
}
.choice-card-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.2rem; height: 2.2rem;
    border-radius: 50%;
    flex: 0 0 auto;
}
.choice-card-body { display: flex; flex-direction: column; gap: 0.25rem; min-width: 0; }
.choice-card-title { font-weight: 600; display: inline-flex; align-items: center; gap: 0.45rem; }
.choice-card-pill {
    font-size: 0.68rem;
    font-weight: 600;
    padding: 0.1rem 0.45rem;
    border-radius: 999px;
    background: var(--icon-purple);
    color: #fff;
    text-transform: uppercase;
    letter-spacing: 0.02em;
}
.choice-card-desc { font-size: 0.85rem; color: var(--muted); line-height: 1.4; }
.choice-card-meta { font-size: 0.82rem; margin-top: 0.15rem; }

/* Env-account modal notice. Markup contract: `.mail-env-notice > i + span`.
   The text MUST sit inside a wrapper (span/div) — otherwise each inline
   fragment becomes its own flex item and column-breaks (see docs/design.md
   §Flex containers with inline text). */
.mail-env-notice {
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    padding: 0.7rem 0.85rem;
    background: var(--icon-purple-soft);
    border-left: 3px solid var(--icon-purple);
    border-radius: var(--radius);
    font-size: 0.85rem;
    line-height: 1.4;
    margin: 0.25rem 0 0.75rem;
}
.mail-env-notice > span { flex: 1 1 auto; min-width: 0; }

/* Direction badge (both type-picker and unified list) */
.mail-direction {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.15rem 0.5rem;
    border-radius: 999px;
    font-size: 0.78rem;
    font-weight: 500;
}
.mail-direction.is-in    { background: var(--icon-green-soft); color: var(--icon-green); }
.mail-direction.is-out   { background: var(--icon-amber-soft); color: var(--icon-amber); }
.mail-direction.is-both  { background: var(--icon-blue-soft); color: var(--accent); }

/* Unified list */
.mail-accounts-list { display: flex; flex-direction: column; gap: 0.5rem; }
.mail-row.is-active    { --row-accent: var(--success); }
.mail-row.is-inactive  { --row-accent: var(--muted); opacity: 0.92; }
/* Env-managed status is signaled via the GRAPH type-badge + INTEGRASJON pill +
   purple icon-circle. No extra row background — that would just be noise. */

/* Mail-row's secondary should be allowed to wrap — server:port + email
   address is often longer than what the desktop grid cell allows, and the
   default list-item-secondary gets ellipsis on desktop that clips mid-address. */
.mail-row .list-item-secondary {
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
}

.mail-type-badge {
    display: inline-block;
    font-size: 0.7rem;
    font-weight: 700;
    padding: 0.12rem 0.4rem;
    border-radius: 4px;
    margin-right: 0.4rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    vertical-align: 1px;
}
.mail-type-badge.type-imap  { background: var(--icon-green-soft); color: var(--icon-green); }
.mail-type-badge.type-smtp  { background: var(--icon-amber-soft); color: var(--icon-amber); }
.mail-type-badge.type-o365  { background: var(--icon-blue-soft); color: var(--accent); }

.mail-env-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    font-size: 0.68rem;
    font-weight: 600;
    padding: 0.1rem 0.4rem;
    border-radius: 999px;
    background: var(--icon-purple);
    color: #fff;
    margin-left: 0.5rem;
    vertical-align: 2px;
    text-transform: uppercase;
    letter-spacing: 0.02em;
}

.mail-meta {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 0.3rem;
}
.mail-last-import { font-size: 0.76rem; }

/* Toggle-pill — clickable pill that shows on/off state and flips on click.
   Generic: used by mail-account direction toggles + scheduler job toggle.
   `data-active="1"` = green (on), `data-active="0"` = grey (off). */
.toggle-pill,
.mail-toggle {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.25rem 0.6rem;
    border-radius: 999px;
    font: inherit;
    font-size: 0.78rem;
    cursor: pointer;
    border: 1px solid var(--border);
    background: transparent;
    color: var(--muted);
    transition: border-color 0.12s, color 0.12s, background 0.12s;
    user-select: none;
}
.toggle-pill[data-active="1"],
.mail-toggle[data-active="1"] {
    border-color: var(--icon-green);
    background: var(--icon-green-soft);
    color: var(--icon-green);
    font-weight: 600;
}
.toggle-pill[data-active="0"]:hover,
.mail-toggle[data-active="0"]:hover {
    border-color: var(--accent);
    color: var(--accent);
    background: var(--accent-soft, var(--surface-2));
}
.toggle-pill[data-active="1"]:hover,
.mail-toggle[data-active="1"]:hover {
    filter: brightness(0.96);
}
.toggle-pill:focus-visible,
.mail-toggle:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}
.toggle-pill i,
.mail-toggle i { font-size: 0.85rem; }

.mail-actions { display: flex; gap: 0.25rem; }

.mail-empty { padding: 1.5rem; text-align: center; font-style: italic; }

/* ----- Compact mail-row (drawer-driven) -----
   Whole row is clickable; small status-dots indicate active directions
   and last-test failure. All actions live in the drawer. */
.mail-row-clickable {
    grid-template-columns: auto 1fr auto auto !important;
    grid-template-areas: "icon primary status chevron" !important;
    column-gap: 0.9rem;
    align-items: center;
    cursor: pointer;
    transition: background 0.12s, border-color 0.12s;
}
.mail-row-clickable:hover { background: var(--surface-2); border-color: var(--accent); }
.mail-row-clickable:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: -2px;
}
.mail-row-icon { grid-area: icon; }
.mail-row-primary {
    grid-area: primary;
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    min-width: 0;
}
.mail-row-primary strong { font-weight: 600; }
.mail-row-sub {
    font-size: 0.8rem;
    color: var(--muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.mail-row-status {
    grid-area: status;
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
}
.mail-row-chevron {
    grid-area: chevron;
    font-size: 0.95rem;
    opacity: 0.6;
}
.mail-row-clickable:hover .mail-row-chevron { opacity: 1; }

/* Status dots — small circular markers next to the chevron. */
.mail-row-dot {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border-radius: 999px;
    font-size: 0.72rem;
    background: var(--shade-2);
    color: var(--muted);
}
.mail-row-dot.is-on   { background: var(--icon-green-soft); color: var(--icon-green); }
.mail-row-dot.is-fail { background: var(--icon-red-soft);   color: var(--icon-red);   }
.mail-row-dot.is-env  { background: var(--icon-purple-soft); color: var(--icon-purple); }

/* ----- Mail-account drawer ----- */
.mail-drawer { display: flex; flex-direction: column; gap: 1.25rem; }
.mail-drawer-head {
    display: flex;
    align-items: center;
    gap: 0.9rem;
    padding-bottom: 1rem;
    border-bottom: 1px solid var(--border);
}
.mail-drawer-head-icon {
    width: 44px; height: 44px;
    border-radius: 10px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 1.2rem;
}
.mail-drawer-head-meta { display: flex; flex-direction: column; gap: 0.15rem; }
.mail-drawer-head-type {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-weight: 600;
}
.mail-drawer-section { display: flex; flex-direction: column; gap: 0.6rem; }
.mail-drawer-section h3 {
    margin: 0;
    font-size: 0.8rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--muted);
}
.mail-drawer-section-hint { margin: 0; font-size: 0.85rem; }
.mail-drawer-toggles { display: flex; flex-direction: column; gap: 0.5rem; }
.mail-drawer-toggle-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    padding: 0.6rem 0.8rem;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--surface-2);
}
.mail-drawer-toggle-info {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    min-width: 0;
}
.mail-drawer-toggle-info strong { font-size: 0.92rem; }
.mail-drawer-toggle-info .muted { font-size: 0.82rem; }
.mail-drawer-test-buttons { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.mail-drawer-tests {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}
.mail-drawer-test-item { padding: 0; }
.mail-drawer-test-button {
    width: 100%;
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    padding: 0.55rem 0.7rem;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--surface);
    color: var(--fg);
    cursor: pointer;
    font: inherit;
    text-align: left;
    transition: background 0.12s, border-color 0.12s;
}
.mail-drawer-test-button:hover { background: var(--surface-2); border-color: var(--accent); }
.mail-drawer-test-button i { font-size: 1rem; margin-top: 0.15rem; }
.mail-drawer-test-item.is-ok    .mail-drawer-test-button i { color: var(--success); }
.mail-drawer-test-item.is-fail  .mail-drawer-test-button i { color: var(--danger); }
.mail-drawer-test-err { display: block; margin-top: 0.2rem; font-size: 0.8rem; }
.mail-drawer-empty { font-size: 0.85rem; }
.mail-drawer-config {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: 0.4rem 0.9rem;
    margin: 0;
    padding: 0.6rem 0.8rem;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: 8px;
    font-size: 0.85rem;
}
.mail-drawer-config dt { color: var(--muted); }
.mail-drawer-config dd {
    margin: 0;
    word-break: break-all;
    font-family: ui-monospace, "SF Mono", Consolas, monospace;
    font-size: 0.82rem;
}
.mail-drawer-danger { border-top: 1px solid var(--border); padding-top: 1rem; }

/* Env-environment-config suggestion banner — only shown when env-vars are set
   and the department doesn't already have an env-driven account. */
.env-suggestion-banner {
    display: flex;
    align-items: center;
    gap: 0.9rem;
    padding: 0.85rem 1rem;
    margin: 0.5rem 0 0.75rem;
    background: var(--icon-purple-soft);
    border: 1px solid var(--icon-purple);
    border-left-width: 3px;
    border-radius: var(--radius);
}
.env-suggestion-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.2rem; height: 2.2rem;
    border-radius: 50%;
    background: var(--icon-purple);
    color: #fff;
    flex: 0 0 auto;
}
.env-suggestion-body { flex: 1 1 auto; min-width: 0; }
.env-suggestion-body strong { display: block; }
.env-suggestion-body p { margin: 0.2rem 0 0; font-size: 0.85rem; line-height: 1.4; }

/* Test result — rendered as a "pseudo-row" below list-item */
.mail-test-result {
    position: relative;
    margin-top: -0.25rem;
    padding: 0.75rem 1rem;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius);
}
.mail-test-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 0.75rem;
    font-size: 0.88rem;
}
.mail-test-grid > div { display: flex; align-items: center; gap: 0.4rem; }
.mail-test-grid i { font-size: 1.1rem; }
.mail-test-messages {
    margin: 0.6rem 0 0;
    padding: 0.5rem 0.75rem;
    list-style: none;
    background: var(--surface);
    border-radius: var(--radius);
    font-size: 0.82rem;
}
.mail-test-messages li { padding: 0.1rem 0; color: var(--muted); }
.mail-test-close {
    position: absolute;
    top: 0.5rem; right: 0.5rem;
    font-size: 0.85rem;
}

/* Mail-fetch-test modal — inbound connection-test that shows last 5 messages.
   Reused by department-mail and global-fallback views via mail-fetch-test.js. */
.mail-fetch-test-status {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.75rem;
    flex-wrap: wrap;
}
.mail-fetch-test-status i { font-size: 1.1rem; }
.mail-fetch-test-error-body {
    background: var(--surface-2, #f6f6f6);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 0.6rem 0.8rem;
    font-size: 0.85rem;
    white-space: pre-wrap;
    word-break: break-word;
}
.mail-fetch-test-list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}
.mail-fetch-test-item {
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 0.6rem 0.8rem;
    background: var(--surface-2, #fafafa);
}
.mail-fetch-test-item-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.3rem;
}
.mail-fetch-test-item-meta {
    display: flex;
    gap: 1rem;
    font-size: 0.82rem;
    flex-wrap: wrap;
    margin-bottom: 0.3rem;
}
.mail-fetch-test-item-snippet {
    margin: 0;
    font-size: 0.85rem;
    line-height: 1.35;
}
.mail-fetch-test-stamp { margin: 0 0 0.5rem 0; font-size: 0.85rem; }
.mail-fetch-test-rerun {
    margin-top: 1rem;
    font-size: 0.85rem;
    border-top: 1px solid var(--border);
    padding-top: 0.6rem;
}

/* "Siste test"-badge — clickable badge in list-item-secondary that opens
   a modal showing the cached result of the most recent send-/fetch-test
   for the row. Inherits .badge / .badge-green / .badge-red base; we only
   add cursor + button-reset since the badge is rendered as <button>. */
.mail-last-test-badge {
    cursor: pointer;
    border: none;
    font: inherit;
    line-height: 1;
}
.mail-last-test-badge:hover { filter: brightness(0.95); }
.mail-last-test-badge i { margin-right: 0.25rem; }

/* Global-mode warning (department mail tab) — only visible when mode ≠ send */
.messaging-warning-banner {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.7rem 0.9rem;
    margin-bottom: 1rem;
    background: var(--icon-amber-soft);
    border-left: 3px solid var(--icon-amber);
    border-radius: var(--radius);
    font-size: 0.88rem;
}
.messaging-warning-banner i { color: var(--icon-amber); font-size: 1.2rem; }
.messaging-warning-banner span { flex: 1 1 auto; }

@media (max-width: 720px) {
    .mail-test-grid { grid-template-columns: 1fr; }
    .mail-meta { align-items: flex-start; }
}


/* Autoassign — one continuous sentence per rule: the whole "[Type] Entity
   → [avatar] Tekniker" lives inside .list-item-primary. Without this
   inline structure, the trigger and assignment would have been rendered as
   two disconnected info boxes with large spacing. The row grid collapses
   to "icon | rule | actions" since tech-info now lives inside primary. */
.list-item-with-actions.autoassign-row {
    grid-template-columns: auto 1fr auto;
    grid-template-areas: "icon primary actions";
}
.autoassign-rule {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
    white-space: normal;
    overflow: visible !important;   /* override .list-item-with-actions ellipsis */
    text-overflow: clip !important;
}
.autoassign-entity-name {
    color: var(--fg);
    font-weight: 600;
}
.autoassign-entity-missing {
    display: inline-flex;
    align-items: baseline;
    gap: 0.35rem;
    color: var(--muted);
}
.autoassign-entity-missing em { font-style: italic; }
.autoassign-entity-id {
    font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
    font-size: 0.85rem;
    color: var(--muted);
}
.autoassign-arrow {
    color: var(--muted);
    font-size: 1.1rem;
    flex-shrink: 0;
    margin: 0 0.25rem;
}
.autoassign-tech {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    color: var(--fg);
}
.autoassign-tech-name { white-space: nowrap; }
.autoassign-tech-name.stale { color: var(--muted); text-decoration: line-through; }

.list-item.is-stale .list-item-icon {
    /* Visual cue: dimmer icon on stale rows so the badge-red carries the
       warning weight without making the whole row scream. */
    opacity: 0.65;
}

/* Modal — pick kind (kategori vs lokasjon). Inline radio-pair styled as
   tab-like segmented control. */
.autoassign-kind-group {
    display: flex; gap: 0.5rem; padding: 0; margin: 0 0 1rem; border: 0;
}
.autoassign-kind-option {
    flex: 1 1 0;
    display: flex; align-items: center; justify-content: center;
    padding: 0.5rem 0.75rem;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
    cursor: pointer;
    user-select: none;
    background: var(--surface);
    transition: background-color 120ms ease, border-color 120ms ease;
}
.autoassign-kind-option:hover { border-color: var(--accent); }
.autoassign-kind-option > input[type="radio"] {
    /* Hide the radio, but preserve accessibility (tab-focus + screen-reader). */
    position: absolute; opacity: 0; pointer-events: none;
}
.autoassign-kind-option > span { display: inline-flex; align-items: center; gap: 0.4rem; }
.autoassign-kind-option:has(input:checked) {
    background: var(--icon-blue-soft);
    border-color: var(--accent);
    color: var(--accent);
}
.autoassign-kind-option:has(input:focus-visible) {
    outline: 2px solid rgba(54, 150, 252, 0.4);
    outline-offset: 1px;
}

/* Notification-drawer sections */
.notif-drawer { display: flex; flex-direction: column; gap: 1.25rem; }
.notif-section h3 {
    font-size: 1rem; font-weight: 600; margin: 0 0 0.5rem;
    padding-bottom: 0.25rem; border-bottom: 1px solid var(--border);
}
.notif-form textarea { min-height: 10rem; }

/* CMDB code-input for JSON */
.code-input {
    font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
    font-size: 0.82rem !important;
}

/* Back-link at the top of category pages */
.back-link {
    display: inline-block;
    margin-bottom: 0.5rem;
    color: var(--muted);
    text-decoration: none;
    font-size: 0.85rem;
}
.back-link:hover { color: var(--accent); }

/* ------ Admin layout follow-ups ------ */

/* Bottom padding on settings tab panel so last item isn't flush with the page end */
.settings-tab-panel {
    padding-bottom: 2rem;
    min-height: 200px;
}

/* Modal/drawer-context override for the user-tabs — settings-page-
   defaults (1.25rem bottom-margin on tabs, 200px min-height + 2rem
   padding-bottom on panel, default p top-margin) all add up to ~50px
   of visual gap between tab strip and the panel intro. Tight modal /
   inline-in-drawer context needs tighter spacing. Scoped via unique
   container classes — sibling-combinator targets panels that follow.

   `.swap-user-tabs` — used in the ticket-swap-user-modal (top-level).
   `.new-ticket-user-tabs-strip` — used inline inside the agent new-
   ticket drawer's BRUKER field; the strip + panels live under the
   `.new-ticket-user-tabs` wrapper but we scope on the strip itself
   so the sibling-combinator works against panels inside the wrapper. */
.swap-user-tabs,
.new-ticket-user-tabs-strip { margin-bottom: 0.5rem; }
.swap-user-tabs ~ .settings-tab-panel,
.new-ticket-user-tabs-strip ~ .settings-tab-panel {
    min-height: 0;
    padding-bottom: 0;
}
.swap-user-tabs ~ .settings-tab-panel > p:first-child,
.new-ticket-user-tabs-strip ~ .settings-tab-panel > p:first-child {
    margin-top: 0.5rem;
}
/* Drawer-context: the "Lag ny"-form inside the new-ticket drawer's
   BRUKER field already lives inside the parent `.admin-form` — kill
   the redundant nested-form spacing so it doesn't double-pad. */
.new-ticket-create-user-form { margin: 0; }
.new-ticket-create-user-hint { font-size: 0.85rem; margin: 0.25rem 0 0.75rem; }

/* (.admin-flag slettet 2026-04-25 — bruk .badge med passende variant.) */

/* Hierarchical indent for nested list-items (e.g. kategori-tre).
   Set `--indent-level: N` inline on the <li> for padding-left offset. */
.list-item[style*="--indent-level"] {
    margin-left: calc(var(--indent-level, 0) * 1.5rem);
}

/* Compact admin-head: smaller bottom gap for use inside drawers/modals
   where vertical space is scarce. */
.admin-head.admin-head-compact { margin-bottom: 0.75rem; }

/* Checkbox row that aligns to the bottom of a sibling form field in a
   flex-row (paired with an input whose label takes the first row). */
.admin-checkbox-row.align-end { align-self: end; }

/* -------------------- Reports (charts) --------------------
   Grid of chart cards used by /agent/reports + /agent/reports/charts.
   Each card is a surface (card-styled) wrapping a fixed-height canvas
   so Chart.js has a bounded box to resize into with
   maintainAspectRatio:false. Daily line chart uses the same card, just
   full-width and taller.
*/

/* Landing: tighten tile row spacing above the snapshot chart grid. */
.reports-tiles { margin-top: 1rem; }
.reports-snapshot { margin-top: 1.5rem; }

/* ---- Varer / Merchandise (/agent/merc) ---- */
.merc-filter {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 0.75rem;
    margin: 1rem 0 1rem;
    align-items: end;
}
.merc-row-body {
    display: flex;
    gap: 0.75rem;
    align-items: center;
}
.merc-thumb {
    width: 56px;
    height: 56px;
    border-radius: var(--radius);
    overflow: hidden;
    background: var(--shade-1);
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}
.merc-thumb img { width: 100%; height: 100%; object-fit: cover; }
.merc-thumb-empty { color: var(--muted); font-size: 1.4rem; }
.merc-row-text { flex: 1; min-width: 0; }
.merc-row-flags { display: flex; gap: 0.5rem; margin-top: 0.25rem; }
.merc-price { font-variant-numeric: tabular-nums; font-weight: 600; white-space: nowrap; }

.merc-cats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 0.3rem 1rem;
}
.merc-form-static {
    padding: 0.6em 0.8em;
    color: var(--muted);
    background: var(--shade-1);
    border-radius: var(--radius);
}
.merc-image-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
    gap: 0.5rem;
    margin: 0.5rem 0;
}
.merc-image-cell {
    position: relative;
    aspect-ratio: 1;
    border: 2px solid var(--border);
    border-radius: var(--radius);
    overflow: hidden;
    background: var(--shade-1);
}
.merc-image-cell.is-primary { border-color: var(--accent); }
.merc-image-cell img { width: 100%; height: 100%; object-fit: cover; }
.merc-image-actions {
    position: absolute;
    bottom: 0.25rem;
    right: 0.25rem;
    display: flex;
    gap: 0.25rem;
    background: rgba(255, 255, 255, 0.9);
    border-radius: var(--radius);
    padding: 0.1rem;
}
.merc-image-badge {
    position: absolute;
    top: 0.25rem;
    left: 0.25rem;
    font-size: 0.7rem;
    font-weight: 600;
    background: var(--accent);
    color: white;
    padding: 0.1rem 0.4rem;
    border-radius: var(--radius);
}
.btn-icon-sm { width: 1.5rem; height: 1.5rem; font-size: 0.8rem; padding: 0; }

/* Note: ingen markup-callsites pr 2026-04-27 — kandidat for sletting. */
.merc-orders-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.9rem;
    overflow: hidden;
}
.merc-orders-table th,
.merc-orders-table td {
    padding: 0.5rem 0.7rem;
    border-bottom: 1px solid var(--border);
    vertical-align: middle;
}
.merc-orders-table th {
    text-align: left;
    font-size: 0.8rem;
    color: var(--muted);
    font-weight: 600;
    background: var(--shade-1);
}
.merc-orders-table tr:last-child td { border-bottom: 0; }
.merc-orders-table .num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }

/* ---- Fakturering (/agent/invoice) ---- */

/* Landing dashboard, top→bottom:
     1. Action tiles (Ufakturerte saker / Fakturahistorikk) — compact,
        side by side
     2. Stat tiles (Fakturert i år / i fjor / Åpne grunnlag)
     3. Donut card "Ufakturert fordelt på kunder"
   Each in its own container so nothing stretches to the donut's height. */
.invoice-action-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 1rem;
    margin-bottom: 1rem;
}
.invoice-action-tile {
    align-self: start;
}

/* Chart rows: donut + bar side by side, then a wide top-customers
   donut below. Each chart card has an explicit-height wrapper since
   Chart.js with maintainAspectRatio:false otherwise collapses to 0px. */
.invoice-charts-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
    gap: 1rem;
    margin-top: 1rem;
}
/* Surface tokens inherited from the canonical row-surface block in main.css. */
.invoice-chart-card {
    padding: 1rem;
    display: flex;
    flex-direction: column;
    margin-top: 1rem;
}
.invoice-charts-row .invoice-chart-card { margin-top: 0; }
.invoice-chart-card h3 {
    margin: 0 0 0.5rem;
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--muted);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.invoice-chart-wrap {
    height: 280px;
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
}
.invoice-chart-wrap-wide { height: 320px; }
.invoice-donut-fallback {
    list-style: none;
    margin: 0;
    padding: 0;
    width: 100%;
    font-size: 0.85rem;
}
.invoice-donut-fallback li {
    display: flex;
    justify-content: space-between;
    padding: 0.25rem 0;
    border-bottom: 1px dashed var(--border);
}
.invoice-donut-fallback li:last-child { border-bottom: 0; }

.invoice-stat-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 1rem;
    margin-bottom: 1.5rem;
}
/* Surface tokens inherited from the canonical row-surface block in main.css. */
.invoice-stat {
    padding: 1rem 1.25rem;
}
.invoice-stat-value {
    font-size: 1.4rem;
    font-weight: 600;
    color: var(--fg);
}
.invoice-stat-label {
    margin-top: 0.25rem;
    font-size: 0.85rem;
    color: var(--muted);
}

/* Hjelp-drawer */
.invoice-help-lede {
    padding: 0.75rem 1rem;
    background: var(--icon-blue-soft);
    border-radius: var(--radius);
    font-size: 0.95rem;
    line-height: 1.5;
    margin: 0 0 1.25rem;
}
.invoice-help-section { margin-bottom: 1.5rem; }
.invoice-help-section h3 {
    margin: 0 0 0.5rem;
    font-size: 1rem;
    font-weight: 600;
}
.invoice-help-section ol,
.invoice-help-section ul { padding-left: 1.25rem; line-height: 1.55; }
.invoice-help-section ol li,
.invoice-help-section ul li { margin-bottom: 0.4rem; }
.invoice-help-layers {
    list-style: none;
    padding-left: 0;
}
.invoice-help-layers li {
    padding: 0.5rem 0.75rem;
    background: var(--shade-1);
    border-radius: var(--radius);
    margin-bottom: 0.5rem;
}
.invoice-help-troubleshoot { padding-left: 1rem; }

.invoice-uninvoiced-hint { margin-bottom: 1rem; }

.invoice-section { margin-top: 2rem; }
.invoice-section .section-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 0.75rem;
}
.invoice-create-bar {
    display: flex;
    align-items: center;
    gap: 0.75rem;
}
.invoice-selection-sum {
    font-size: 0.9rem;
    font-variant-numeric: tabular-nums;
}

/* Surface tokens inherited from the canonical row-surface block in main.css. */
.invoice-customer {
    padding: 0.75rem 1rem;
}
.invoice-customer-head {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.5rem;
}
.invoice-customer.is-collapsed .invoice-customer-head { margin-bottom: 0; }
.invoice-customer.is-collapsed .invoice-uninvoiced-table { display: none; }

.invoice-customer-select {
    display: inline-flex;
    align-items: center;
    cursor: pointer;
}
.invoice-customer-toggle {
    flex: 1;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    background: transparent;
    border: 0;
    padding: 0.25rem 0;
    font: inherit;
    color: inherit;
    text-align: left;
    cursor: pointer;
}
.invoice-customer-toggle:hover .invoice-customer-name { text-decoration: underline; }
.invoice-customer-chev {
    transition: transform 0.15s ease;
    color: var(--muted);
    width: 1rem;
    text-align: center;
}
.invoice-customer:not(.is-collapsed) .invoice-customer-chev { transform: rotate(90deg); }
.invoice-customer-name { font-weight: 600; }

/* Three fixed-width meta columns on the right, so saker-count / tid /
   varer-sum line up vertically across customer rows. tabular-nums keeps
   digit widths consistent, right-align ensures the column edges match. */
.invoice-customer-meta {
    margin-left: auto;
    display: flex;
    gap: 1.25rem;
    font-size: 0.85rem;
    flex-shrink: 0;
}
.invoice-customer-meta > span {
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.invoice-customer-meta-saker { min-width: 5rem; }
.invoice-customer-meta-tid   { min-width: 4rem; }
.invoice-customer-meta-varer { min-width: 6rem; }
/* Narrow viewports: the fixed-width meta columns (5+4+6rem ≈ 240px)
 * + flex-shrink: 0 force themselves onto the same row as the name —
 * with a long customer name the rightmost number ("varer") runs past
 * the card edge. Drop the meta to its own row below the header and
 * remove the min-widths so cells size to content. */
@media (max-width: 720px) {
    .invoice-customer-head { flex-wrap: wrap; }
    .invoice-customer-meta {
        flex-basis: 100%;
        margin-left: 0;
        margin-top: 0.25rem;
        justify-content: flex-end;
    }
    .invoice-customer-meta-saker,
    .invoice-customer-meta-tid,
    .invoice-customer-meta-varer { min-width: 0; }
}
.invoice-uninvoiced-table,
.invoice-history-table,
.invoice-lines-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.9rem;
}
.invoice-uninvoiced-table th,
.invoice-history-table th,
.invoice-lines-table th {
    font-weight: 600;
    color: var(--muted);
    text-align: left;
    font-size: 0.8rem;
    padding: 0.4rem 0.6rem;
    border-bottom: 1px solid var(--border);
}
.invoice-uninvoiced-table td,
.invoice-history-table td,
.invoice-lines-table td {
    padding: 0.45rem 0.6rem;
    border-bottom: 1px solid var(--border);
    vertical-align: middle;
}
.invoice-uninvoiced-table tr:last-child td,
.invoice-history-table tr:last-child td,
.invoice-lines-table tr:last-child td { border-bottom: 0; }
.invoice-uninvoiced-table .num,
.invoice-history-table .num,
.invoice-lines-table .num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.invoice-uninvoiced-table .cb-cell { width: 2rem; }
/* Merchandise sub-row indented under its parent ticket-row, no border
   between sub-rows so they read as a continuation. Mobile (<720px)
   moves the shading from td onto the tr — see media block below. */
.invoice-merch-row td { background: var(--shade-1); }
.invoice-merch-row + .invoice-merch-row td { border-top: 0; }

/* Mobile: stack table rows as cards. Each <td> becomes its own line,
 * <thead> hides — matches the log-table pattern in this file. Numeric
 * columns left-align since right-aligned numbers in a stacked list
 * reads strange without their original column header. */
@media (max-width: 720px) {
    .invoice-uninvoiced-table thead,
    .invoice-history-table thead,
    .invoice-lines-table thead { display: none; }
    .invoice-uninvoiced-table tr,
    .invoice-history-table tr,
    .invoice-lines-table tr {
        display: block;
        padding: 0.6rem 0.75rem;
        border-bottom: 1px solid var(--border);
    }
    .invoice-uninvoiced-table td,
    .invoice-history-table td,
    .invoice-lines-table td {
        display: block;
        padding: 0.15rem 0;
        border: none;
    }
    /* Empty cells (cb-cell on merch rows, the "Sak" / "Timer" cells that
     * a merch line doesn't fill) become blank vertical strips on mobile —
     * collapse them so the row reads tightly. The .is-empty-num class
     * tags num-cells whose value is "–" — those have no column header
     * to give them context on mobile, so we hide them too. */
    .invoice-uninvoiced-table td:empty,
    .invoice-history-table td:empty,
    .invoice-lines-table td:empty,
    .invoice-uninvoiced-table .num.is-empty-num,
    .invoice-history-table .num.is-empty-num,
    .invoice-lines-table .num.is-empty-num { display: none; }
    .invoice-uninvoiced-table .num,
    .invoice-history-table .num,
    .invoice-lines-table .num { text-align: left; white-space: normal; }

    /* Ticket rows: lay out as a single flex line so the ticket number,
     * title, and sum sit side-by-side instead of stacking the way the
     * generic block-table-collapse would do. Title takes the flex
     * remainder; the sum hugs the right edge. */
    .invoice-uninvoiced-table tr:not(.invoice-merch-row),
    .invoice-history-table tr:not(.invoice-merch-row),
    .invoice-lines-table tr:not(.invoice-merch-row) {
        display: flex;
        align-items: baseline;
        flex-wrap: wrap;
        gap: 0.4rem 0.6rem;
    }
    /* Third td (title) is the only one that should grow; the rest size
     * to content. Selector targets the title via column position since
     * the title td has no class of its own. */
    .invoice-uninvoiced-table tr:not(.invoice-merch-row) > td:nth-child(3),
    .invoice-history-table tr:not(.invoice-merch-row) > td:nth-child(3),
    .invoice-lines-table tr:not(.invoice-merch-row) > td:nth-child(3) {
        flex: 1;
        min-width: 8rem;
    }
    .invoice-uninvoiced-table tr:not(.invoice-merch-row) > td.num,
    .invoice-history-table tr:not(.invoice-merch-row) > td.num,
    .invoice-lines-table tr:not(.invoice-merch-row) > td.num {
        flex-shrink: 0;
        font-weight: 600;
    }

    /* Merch rows render as compact one-line entries below their parent
     * ticket. Flex layout puts title (icon + name + qty/price) on the
     * left and sum on the right; flex-wrap lets long titles drop to a
     * second line above the sum. The whole row carries the shade-1
     * background (was on td in desktop) so consecutive merch rows merge
     * into one continuous shaded block instead of looking like separate
     * cards with gaps between them. */
    .invoice-merch-row {
        display: flex;
        align-items: center;
        flex-wrap: wrap;
        gap: 0.5rem 0.75rem;
        padding-left: 1.75rem;
        background: var(--shade-1);
    }
    .invoice-merch-row td { background: transparent; }
    .invoice-merch-row .invoice-merch-title { flex: 1; min-width: 0; }
    .invoice-merch-row .num {
        flex-shrink: 0;
        text-align: right;
        white-space: nowrap;
        font-weight: 600;
    }
    /* Within a ticket+merch group, no internal border-bottoms — the
     * shared shade reads as "this all belongs together". The next ticket
     * (a non-merch tr) keeps its bottom border, marking the new group. */
    .invoice-uninvoiced-table tr:has(+ .invoice-merch-row),
    .invoice-merch-row:has(+ .invoice-merch-row) { border-bottom: 0; }
}

/* Empty-state shown when there are no unbilled timereg or merch rows
   in the user's department-scope. Friendly explanation rather than a
   bare "ingen treff"-line so leaders understand WHY the list is empty. */
.invoice-empty-state {
    text-align: center;
    padding: 2rem 1rem;
    color: var(--muted);
}
.invoice-empty-state i {
    font-size: 2.5rem;
    color: var(--icon-green);
    margin-bottom: 0.75rem;
    display: block;
}
.invoice-empty-state h3 {
    margin: 0 0 0.5rem;
    font-size: 1rem;
    font-weight: 600;
    color: var(--fg);
}
.invoice-empty-state p {
    max-width: 480px;
    margin: 0 auto;
    line-height: 1.5;
    font-size: 0.9rem;
}

.invoice-merch-title {
    color: var(--muted);
    font-size: 0.85rem;
    padding-left: 1.5rem !important;
}
.invoice-merch-title .muted { margin-left: 0.5rem; }

/* Editable invoice-lines table — shown in the invoice-detail modal when
   the invoice is not yet sent. Each cell with a data-line-field has an
   inline input. */
.invoice-lines-editable input[type="text"],
.invoice-lines-editable input[type="number"] {
    width: 100%;
    padding: 0.25rem 0.4rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    color: var(--fg);
    font-size: 0.85rem;
    font-family: inherit;
}
.invoice-lines-editable input.invoice-line-qty,
.invoice-lines-editable input.invoice-line-price {
    width: 90px;
    text-align: right;
}
.invoice-lines-foot-label {
    text-align: right;
    color: var(--muted);
    font-size: 0.85rem;
}
.invoice-lines-add { margin-top: 0.75rem; }
/* Surface tokens inherited from the canonical row-surface block in main.css. */
.invoice-history-table {
    overflow: hidden;
}
.invoice-confirm-list { margin: 0.5rem 0; padding-left: 1.25rem; color: var(--muted); }
.invoice-detail-meta {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 0.4rem 1.5rem;
    margin-bottom: 1rem;
    padding: 0.75rem;
    background: var(--shade-1);
    border-radius: var(--radius);
    font-size: 0.9rem;
}

/* ---- Reports: feedback (/agent/reports/feedback) ---- */
.reports-filter {
    display: flex;
    gap: 0.75rem;
    align-items: end;
    margin: 1rem 0 1.5rem;
    flex-wrap: wrap;
}
.reports-filter label {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    font-size: 0.85rem;
    color: var(--muted);
}
.reports-filter input[type="date"] {
    padding: 0.4rem 0.6rem;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
    font-family: inherit;
    font-size: 0.95rem;
}
.fb-summary {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 2fr;
    gap: 1.5rem;
    margin-bottom: 2rem;
}
@media (max-width: 720px) {
    .fb-summary { grid-template-columns: 1fr; }
}
/* Surface inherited from the :is() block in main.css. */
.fb-total {
    padding: 1.5rem;
    text-align: center;
}
.fb-total-value { font-size: 2.75rem; font-weight: 700; color: var(--accent); line-height: 1; }
.fb-total-label { color: var(--muted); margin-top: 0.4rem; }
.fb-total-sub { color: var(--muted); font-size: 0.85rem; margin-top: 0.4rem; }
.fb-stats {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 1rem;
}
.fb-stat {
    padding: 1rem 1.25rem;
    text-align: center;
}
.fb-stat-value { font-size: 2rem; font-weight: 600; color: var(--fg); }
.fb-stat-max { font-size: 1rem; color: var(--muted); margin-left: 0.15rem; }
.fb-stat-label { color: var(--muted); font-size: 0.9rem; margin-top: 0.3rem; }
.fb-distribution {
    padding: 1.25rem;
}
.fb-distribution h2 { margin: 0 0 1rem; font-size: 1.05rem; font-weight: 600; }
.fb-bars { display: grid; gap: 0.5rem; }
.fb-bar-row {
    display: grid;
    grid-template-columns: 3.5rem 1fr 3rem;
    gap: 0.6rem;
    align-items: center;
}
.fb-bar-label { color: var(--muted); font-size: 0.9rem; }
.fb-bar-track {
    background: var(--shade-1);
    border-radius: 999px;
    height: 0.9rem;
    overflow: hidden;
}
.fb-bar-fill {
    width: var(--bar-w, 0%);
    background: var(--bar-bg, var(--accent));
    height: 100%;
    border-radius: 999px;
    transition: width 0.3s ease;
}
.fb-bar-value { text-align: right; color: var(--fg); font-variant-numeric: tabular-nums; font-size: 0.9rem; }

/* -------------------- Reports: ticketfilter (Saksfiltrering) --------
   Chip-multi-select used as a form field. Each .ff-multi wraps a label
   + a .chip-input box that matches the .log-filter input height/border
   so fields line up across rows. The + button sits inline with chips.
*/
.ff-multi {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    font-size: 0.85rem;
    min-width: 0;  /* allow grid to shrink this cell */
}
/* `.ff-multi .chip-input` previously redeclared visual tokens — extracted
   to the canonical `.chip-input` rule in main.css. The only context-
   specific tweak this wrapper needs is `position: relative` so the
   placeholder underneath can absolute-position itself within the host. */
.ff-multi .chip-input {
    position: relative;
}
.ff-multi .chip-input-list {
    flex: 1 1 auto;
    min-height: unset;
    min-width: 0;
}
.ff-multi .chip-input-placeholder {
    position: absolute;
    left: 0.6rem;
    top: 50%;
    transform: translateY(-50%);
    pointer-events: none;
    font-size: 0.9rem;
}
.ff-multi .chip-add {
    flex-shrink: 0;
    margin-left: auto;
}

.filter-result-table a { color: var(--accent); text-decoration: none; }
.filter-result-table a:hover { text-decoration: underline; }
.filter-result-table .avatar-xs {
    width: 20px; height: 20px; font-size: 0.65rem;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: 50%; background: var(--icon-blue-soft); color: var(--accent);
    margin-right: 0.35rem; vertical-align: middle;
}
.filter-result-table .user-link { cursor: pointer; }
.filter-result-table .user-link:hover { color: var(--accent); }

/* Disabled tile variant — for features we show in the nav but haven't
   built yet (e.g. Tilbakemelding waiting on feedback flow). Renders as
   a non-interactive <div> styled like a muted tile. */
.tile.is-disabled {
    opacity: 0.55;
    cursor: not-allowed;
    pointer-events: none;
}
.tile.is-disabled:hover {
    transform: none;
    border-color: var(--border);
    box-shadow: 0 1px 2px rgba(0,0,0,0.04);
}

.report-charts-grid {
    display: grid;
    /* Fixed 2 columns on desktop so .span-2 always means "full
       width" and .span-1 always means "half width" — without
       auto-fit surprises when the number of data points or screen
       size changes. */
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1rem;
    margin-top: 1rem;
}
@media (max-width: 760px) {
    .report-charts-grid {
        grid-template-columns: 1fr;
    }
}
/* Surface inherited from .surface-utility in markup. Only structure here. */
.report-chart-card {
    padding: 1rem;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}
/* Charts that benefit from extra horizontal room (bar charts with
   many items: kunder/tjeneste/lokasjon/kategori) — span the full row. */
.report-chart-card-span-2 {
    grid-column: 1 / -1;
}
.report-chart-card h3 {
    margin: 0;
    font-size: 1.05rem;
    font-weight: 600;
}
.report-chart-subtitle {
    margin: -0.25rem 0 0 0;
    font-size: 0.78rem;
    line-height: 1.2;
}
.report-chart-canvas-wrap {
    position: relative;
    height: 280px;
}
.report-chart-daily {
    margin-top: 1rem;
}
.report-chart-daily .report-chart-canvas-wrap {
    height: 340px;
}
.report-chart-empty {
    margin: 0;
    padding: 0.5rem 0;
    font-size: 0.9rem;
}

/* Integrations (/agent/settings/integrations).
   Tile grid on the landing, detail page per integration. */
.integrations-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
    gap: 1rem;
    margin-top: 1rem;
}
/* Surface + hover-lift inherited via `.surface` + `a.surface` selectors
   in markup. Only structure here. */
.integration-tile {
    display: grid;
    grid-template-columns: auto 1fr auto;
    align-items: center;
    gap: 1rem;
    padding: 1.1rem 1.25rem;
    text-decoration: none;
    color: var(--fg);
}
.integration-tile-logo {
    flex: 0 0 auto;
    width: 56px;
    height: 56px;
    border-radius: 10px;
    background: var(--logo-backdrop);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 8px;
    box-shadow: inset 0 0 0 1px var(--border);
}
.integration-tile-logo svg { width: 100%; height: 100%; display: block; }
.integration-tile-logo-fa {
    background: var(--surface-2);
    color: var(--accent);
    font-size: 1.6rem;
}
.integration-tile-body {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    min-width: 0;
}
.integration-tile-title { font-size: 1.05rem; font-weight: 600; line-height: 1.2; }
.integration-tile-subtitle {
    color: var(--muted);
    font-size: 0.88rem;
    line-height: 1.35;
}
.integration-tile-status {
    font-size: 0.82rem;
    margin-top: 0.25rem;
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
}
.integration-tile-status.is-on  { color: var(--icon-green, #16a34a); }
.integration-tile-status.is-off { color: var(--muted); }
.integration-tile-chevron {
    color: var(--muted);
    font-size: 1rem;
}

/* Detail page */
.integration-detail-head {
    display: flex;
    align-items: center;
    gap: 1.25rem;
    margin: 0.5rem 0 1.25rem;
}
.integration-detail-logo {
    flex: 0 0 auto;
    width: 80px;
    height: 80px;
    border-radius: 14px;
    background: var(--logo-backdrop);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 14px;
    box-shadow: inset 0 0 0 1px var(--border);
}
.integration-detail-logo svg { width: 100%; height: 100%; display: block; }
.integration-detail-logo-fa {
    background: var(--surface-2);
    color: var(--accent);
    font-size: 2.4rem;
}
.integration-detail-head-body h1 { margin: 0 0 0.2rem; }
.integration-detail-head-body .muted { margin: 0; }

.integration-detail-help {
    margin: 1rem 0 1.5rem;
    padding: 1rem 1.25rem;
    background: var(--surface-2);
    border-radius: 8px;
    border-left: 3px solid var(--accent);
    line-height: 1.55;
}
.integration-detail-help code {
    background: var(--surface);
    padding: 0.1rem 0.35rem;
    border-radius: 3px;
    font-size: 0.9em;
}
/* The width comes from the `.content-narrow` wrapper — don't hard-code here
   (docs/design.md §Content widths). The form fills the container. */

/* Test-result banner on the integration detail page */
.integration-test-result {
    margin: 0.5rem 0 1rem;
    padding: 0.75rem 1rem;
    border-radius: 6px;
    border-left: 3px solid var(--muted);
    background: var(--surface-2);
    font-size: 0.9rem;
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    line-height: 1.45;
}
.integration-test-result i { flex: 0 0 auto; margin-top: 0.15rem; font-size: 1.05rem; }
.integration-test-result.is-loading { border-left-color: var(--accent); color: var(--muted); }
.integration-test-result.is-ok      { border-left-color: var(--icon-green, #16a34a); }
.integration-test-result.is-ok i    { color: var(--icon-green, #16a34a); }
.integration-test-result.is-error   { border-left-color: var(--icon-red, #ef4444); }
.integration-test-result.is-error i { color: var(--icon-red, #ef4444); }
/* Sync progress inside .integration-test-result. Wrapped in a
   .integration-sync-content column so the spinner icon on the left
   stays on the top line while progress-bar + hint stack below the text. */
.integration-test-result .integration-sync-content {
    flex: 1;
    min-width: 0;
}
.integration-test-result .integration-sync-progress {
    width: 100%;
    height: 6px;
    margin-top: 0.5rem;
    background: var(--shade-2);
    border-radius: 3px;
    overflow: hidden;
}
.integration-test-result .integration-sync-progress-bar {
    width: var(--progress, 0%);
    height: 100%;
    background: var(--accent);
    transition: width 0.4s ease;
}
.integration-test-result .integration-sync-hint {
    margin: 0.4rem 0 0;
    font-size: 0.8rem;
}

/* select-remote: dropdown + «Hent» button side by side, with a small
   feedback line below. Currently used by AI Gateway for the model picker. */
.integration-remote-choice-row {
    display: flex;
    gap: 0.5rem;
    align-items: stretch;
}
.integration-remote-choice-row select { flex: 1 1 auto; min-width: 0; }
.integration-remote-choice-row .btn { flex: 0 0 auto; }
.integration-remote-choice-msg {
    margin: 0.35rem 0 0;
    font-size: 0.85rem;
    color: var(--muted);
}
.integration-remote-choice-msg.is-ok    { color: var(--icon-green, #16a34a); }
.integration-remote-choice-msg.is-error { color: var(--icon-red, #ef4444); }

/* AI-suggestion modal — opened from the comment form's «Foreslå svar (AI)» link.
   Shows loading → result (textarea) or error, with an action row at the bottom. */
.ai-suggest-loading,
.ai-suggest-error {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 1rem 0.25rem;
    line-height: 1.4;
}
.ai-suggest-loading i { color: var(--accent); font-size: 1.25rem; }
.ai-suggest-error i   { color: var(--icon-red, #ef4444); font-size: 1.25rem; flex: 0 0 auto; }
.ai-suggest-loading p,
.ai-suggest-error p { margin: 0; }

.ai-suggest-meta {
    margin: 0 0 0.6rem;
    font-size: 0.85rem;
    color: var(--muted);
    display: flex;
    align-items: center;
    gap: 0.4rem;
}
.ai-suggest-meta i { color: var(--icon-blue, #2563eb); }

.ai-suggest-text {
    width: 100%;
    min-height: 220px;
    padding: 0.75rem;
    border: 1px solid var(--border-strong);
    border-radius: 6px;
    font-family: inherit;
    font-size: 0.95rem;
    line-height: 1.5;
    background: var(--surface);
    color: var(--fg);
    resize: vertical;
}
.ai-suggest-text:focus { outline: 2px solid var(--accent); outline-offset: -1px; }

.ai-suggest-actions {
    display: flex;
    justify-content: flex-end;
    gap: 0.5rem;
    margin-top: 0.75rem;
}

/* Test-system-prompt modal — opened from ai_gateway-settings to
   verify that the prompt produces the desired behavior before saving. */
.ai-test-meta {
    margin: 0 0 0.75rem;
    font-size: 0.85rem;
    color: var(--muted);
    line-height: 1.45;
}
.ai-test-question {
    width: 100%;
    min-height: 90px;
    padding: 0.6rem 0.75rem;
    border: 1px solid var(--border-strong);
    border-radius: 6px;
    font-family: inherit;
    font-size: 0.95rem;
    line-height: 1.45;
    resize: vertical;
    background: var(--surface);
    color: var(--fg);
}
.ai-test-actions {
    display: flex;
    justify-content: flex-end;
    gap: 0.5rem;
    margin-top: 0.75rem;
}
.ai-test-result {
    margin-top: 1rem;
    padding: 0.8rem 1rem;
    border-radius: 6px;
    border-left: 3px solid var(--muted);
    background: var(--surface-2);
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}
.ai-test-result.is-ok    { border-left-color: var(--icon-green, #16a34a); }
.ai-test-result.is-error {
    border-left-color: var(--icon-red, #ef4444);
    flex-direction: row;
    align-items: flex-start;
    gap: 0.6rem;
}
.ai-test-result.is-error i { color: var(--icon-red, #ef4444); font-size: 1.2rem; margin-top: 0.1rem; }
.ai-test-result.is-error strong { display: block; margin-bottom: 0.2rem; }
.ai-test-result.is-error p { margin: 0; }
.ai-test-result-head {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.85rem;
    color: var(--muted);
}
.ai-test-result-head i { color: var(--icon-blue, #2563eb); }
.ai-test-result-body {
    margin: 0;
    padding: 0.75rem;
    background: var(--surface);
    border-radius: 4px;
    font-family: inherit;
    font-size: 0.95rem;
    line-height: 1.55;
    white-space: pre-wrap;
    word-wrap: break-word;
    max-height: 400px;
    overflow-y: auto;
}

/* Scheduler v2 — /agent/settings/scheduler. */
.scheduler-job-key {
    margin-left: 0.5rem;
    font-size: 0.75rem;
    background: var(--surface-2);
    padding: 0.1rem 0.4rem;
    border-radius: 3px;
    color: var(--muted);
}
.scheduler-detail { display: grid; grid-template-columns: 8rem 1fr; gap: 0.35rem 0.8rem; margin: 0.75rem 0; }
.scheduler-detail dt { color: var(--muted); }
.scheduler-detail dd { margin: 0; }
.scheduler-config {
    margin: 0;
    background: var(--surface-2);
    padding: 0.5rem;
    font-size: 0.8rem;
    white-space: pre-wrap;
    border-radius: 3px;
}
.scheduler-feedback-head { margin-top: 1rem; font-size: 0.9rem; }
.scheduler-feedback {
    background: var(--surface-2);
    padding: 0.5rem;
    font-size: 0.82rem;
    white-space: pre-wrap;
    word-break: break-word;
    border-radius: 3px;
    max-height: 300px;
    overflow-y: auto;
}

/* -------------------- Product-detail drawer --------------------
   Read-only product view, opened from the Varer-tab on a ticket and
   from /agent/merc/items. Footer is route-aware (see
   views/product-detail-drawer.js) — when on a ticket-detail URL it
   shows a "Legg til på sak #X"-button that POSTs to the merchandise-
   add endpoint. */
.product-detail-hero {
    margin: -1.25rem -1.25rem 1rem;
    background: var(--shade-1);
    aspect-ratio: 16 / 9;
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
}
.product-detail-hero img {
    width: 100%;
    height: 100%;
    object-fit: contain;
    display: block;
}
.product-detail-hero-empty { color: var(--muted); font-size: 3rem; }
.product-detail-body { display: flex; flex-direction: column; gap: 0.75rem; }
.product-detail-badges { display: flex; flex-wrap: wrap; gap: 0.35rem; }
.product-detail-title { margin: 0; font-size: 1.15rem; line-height: 1.3; }
.product-detail-short { margin: 0; font-size: 0.9rem; }
.product-detail-price {
    display: flex;
    align-items: baseline;
    gap: 0.4rem;
    padding: 0.6rem 0.8rem;
    background: var(--shade-1);
    border-radius: var(--radius);
}
.product-detail-price strong { font-size: 1.1rem; }
.product-detail-section {
    margin-top: 1.25rem;
    padding-top: 1.25rem;
    border-top: 1px solid var(--border);
}
.product-detail-section h3 {
    margin: 0 0 0.4rem;
    font-size: 0.78rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--muted);
}
/* Description clamp + Vis-mer toggle. Mirrors quickview-description-*
   pattern used on the ticket-detail drawer. */
.product-detail-description-body {
    max-height: 12em;
    overflow: hidden;
    position: relative;
}
.product-detail-description-body.is-expanded { max-height: none; }
.product-detail-description-body:not(.is-expanded)::after {
    content: '';
    position: absolute;
    bottom: 0; left: 0; right: 0;
    height: 3em;
    background: linear-gradient(transparent, var(--surface));
    pointer-events: none;
}
.product-detail-description-toggle { margin-top: 0.4rem; }

.product-detail-meta {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: 0.25rem 1rem;
    margin: 0;
    font-size: 0.88rem;
}
.product-detail-meta dt { color: var(--muted); }
.product-detail-meta dd { margin: 0; }
.product-detail-links { list-style: none; margin: 0; padding: 0; }
.product-detail-links li { margin-bottom: 0.25rem; }
.product-detail-links a { color: var(--accent); text-decoration: none; }
.product-detail-links a:hover { text-decoration: underline; }
.product-detail-footer {
    margin-top: 1rem;
    padding-top: 1rem;
    border-top: 1px solid var(--border);
}
.product-detail-footer .btn { width: 100%; }
.product-detail-footer-hint {
    margin: 0;
    font-size: 0.85rem;
    text-align: center;
}

/* -------------------- Ticket Varer-tab --------------------
   Tekniker-side merchandise on a ticket. Each row is a flat card with
   product info on the left, qty input center, price right, and a
   delete-button trailing. Locked rows (delivered / invoiced) gray
   the qty + show a lock-icon instead of delete. */
.ticket-merch { display: flex; flex-direction: column; gap: 0.75rem; }
.ticket-merch-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
}
.ticket-merch-title { margin: 0; font-size: 1rem; font-weight: 600; }
.ticket-merch-empty { padding: 1rem 0; }

.ticket-merch-picker {
    padding: 0.75rem;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius);
}
.ticket-merch-picker .admin-form-label {
    display: block;
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--muted);
    text-transform: uppercase;
    letter-spacing: 0.03em;
    margin-bottom: 0.4rem;
}

.ticket-merch-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}
.ticket-merch-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 130px 130px 40px;
    align-items: center;
    gap: 0.75rem;
    padding: 0.6rem 0.8rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
}
.ticket-merch-row.is-locked { background: var(--shade-1); }
.ticket-merch-row-main { min-width: 0; }
.ticket-merch-row-title {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    flex-wrap: wrap;
    font-size: 0.95rem;
}
.ticket-merch-title-link {
    color: inherit;
    text-decoration: none;
    cursor: pointer;
    border-bottom: 1px dashed transparent;
    transition: border-color 100ms ease, color 100ms ease;
}
.ticket-merch-title-link:hover {
    color: var(--accent);
    border-bottom-color: var(--accent);
}
.ticket-merch-row-desc {
    font-size: 0.82rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ticket-merch-row-qty {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    min-width: 0;
}
.ticket-merch-qty-label {
    font-size: 0.7rem;
    color: var(--muted);
    text-transform: uppercase;
    letter-spacing: 0.03em;
}
.ticket-merch-qty-input-wrap {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
}
.ticket-merch-qty-input {
    /* 76px fits 4 digits ("9999") plus the native spinner arrows on
       Chromium/Safari without clipping. */
    width: 76px;
    padding: 0.3rem 0.5rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    font-size: 0.9rem;
    background: var(--surface);
    color: var(--fg);
    text-align: right;
}
.ticket-merch-qty-input:disabled { background: var(--shade-2); color: var(--muted); }
.ticket-merch-row-unit { font-size: 0.85rem; white-space: nowrap; }

.ticket-merch-row-price {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    text-align: right;
    font-size: 0.82rem;
}
.ticket-merch-row-price strong { font-size: 0.95rem; }

.ticket-merch-row-actions {
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.ticket-merch-row-actions .muted i { font-size: 0.95rem; }

.ticket-merch-total {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    padding: 0.6rem 0.8rem;
    margin-top: 0.25rem;
    border-top: 2px solid var(--border);
    font-size: 0.95rem;
}
.ticket-merch-total strong { font-size: 1rem; }

@media (max-width: 720px) {
    .ticket-merch-row {
        grid-template-columns: 1fr;
        gap: 0.4rem;
    }
    .ticket-merch-row-price {
        align-items: flex-start;
        text-align: left;
        flex-direction: row;
        gap: 0.5rem;
    }
    .ticket-merch-row-actions { justify-content: flex-end; }
}

/* -------------------- DataTable component --------------------
   Compact, mobile-friendly tabular listing. Used for "report"-style
   views (ticketfilter, without-service, …) — read once, not lived-in,
   so it's compressed: header on top, single-line rows below, small
   text, small avatars. On mobile (<720px) the header collapses and
   each row becomes a rounded card with label/value pairs stacked.

   The component sets `--dt-cols` as inline style on the host so column
   count + widths are dynamic. Header AND every row share that track
   so columns always line up. See components/data-table.js. */
.data-table-body {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    margin: 0;
}

/* Header: hidden on mobile, per-row labels take over. */
.data-table-header { display: none; }
@media (min-width: 720px) {
    .data-table-header {
        display: grid;
        grid-template-columns: var(--dt-cols);
        column-gap: 1rem;
        align-items: center;
        padding: 0.35rem 0.8rem;
        /* Transparent border matches the rows' 1px border so content-box
           widths line up exactly. */
        border: 1px solid transparent;
    }
    .data-table-head-cell {
        font-size: 0.7rem;
        font-weight: 600;
        color: var(--muted);
        text-transform: uppercase;
        letter-spacing: 0.04em;
    }
    .data-table-head-cell.is-right { text-align: right; }
}

/* Row: rounded card on mobile, single grid row on desktop. row-gap only
   matters on mobile where cells stack vertically — desktop's single-row
   grid makes it a no-op. */
.data-table-row {
    display: grid;
    grid-template-columns: 1fr;
    row-gap: 0.6rem;
    padding: 0.6rem 0.8rem;
    font-size: 0.82rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    color: var(--fg);
    text-decoration: none;
    cursor: pointer;
}
.data-table-row:hover { border-color: var(--accent); }
.data-table-primary {
    font-size: 0.85rem;
    font-weight: 500;
    /* Truncate when the title doesn't fit — prevents a 2-line wrap that
       would push the row taller and break alignment. */
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
}
.data-table-cell {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    min-width: 0;
}
.data-table-cell-label {
    font-size: 0.7rem;
    color: var(--muted);
    text-transform: uppercase;
    letter-spacing: 0.03em;
}
.data-table-cell-value {
    font-size: 0.82rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}
.data-table-empty { padding: 1rem 0; }

/* Desktop: rows reuse the shared track so cells line up under the
   header. Auto-placement (no explicit grid-area) so hiding cells via
   `display: none` at narrower viewports doesn't leave empty tracks —
   the visible cells flow into the available cols in DOM order.
   `grid-template-rows` + `grid-auto-rows: 0` defend against any
   implicit row creation. */
@media (min-width: 720px) {
    .data-table-row,
    .data-table-header {
        grid-template-columns: var(--dt-cols);
    }
    .data-table-row {
        grid-template-rows: minmax(0, auto);
        grid-auto-rows: 0;
        grid-auto-flow: column;
        column-gap: 1rem;
        align-items: center;
    }
    .data-table-cell-label { display: none; }
    .data-table-cell.is-right { text-align: right; }
    .data-table-cell.is-right .data-table-cell-value { text-align: right; }
}

/* Three-tier priority system. Each column declares `priority: 1|2|3`
   (default 1). Lower-priority numbers stay visible longer — priority-3
   drops first when the viewport gets crowded.
   - 1400px+:    all visible
   - 1200-1399:  drop priority-3
   - 720-1199:   drop priority-2+3 (only priority-1 visible)
   - <720px:     mobile stack (everything visible, label/value form)
   The JS computes one --dt-cols-N variant per tier so grid tracks
   shrink to match the visible cells. */
@media (min-width: 720px) and (max-width: 1399px) {
    .data-table-cell--p3,
    .data-table-head-cell--p3 { display: none; }
    .data-table-row,
    .data-table-header {
        grid-template-columns: var(--dt-cols-2);
    }
}
@media (min-width: 720px) and (max-width: 1199px) {
    .data-table-cell--p2,
    .data-table-head-cell--p2 { display: none; }
    .data-table-row,
    .data-table-header {
        grid-template-columns: var(--dt-cols-1);
    }
}

/* Inline avatar+name combo. Generic helper used inside data-table cells
   (Bruker, Tekniker) and elsewhere. Small avatar for dense layouts. */
.user-inline {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    min-width: 0;
}
.user-inline > span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.user-inline .avatar.avatar-xs {
    width: 18px;
    height: 18px;
    font-size: 0.6rem;
    flex-shrink: 0;
}

/* -------------------- Reports scope-bar --------------------
   Compact toolbar of dropdown-pills used to filter a list/report. Each
   pill renders as `[icon] Label: VALUE [▾]`. The menu opens with a list
   of selectable options (checkboxes for multi, radios for single). Style
   is intentionally low-contrast — filter selection is a rare action and
   shouldn't compete with the content below.
   Generic primitive — see docs/components/toolbar-filter.md. Used by
   reports-scope (multi-select dept+team) and merc-orders (single-select
   status+dept), and any future filter bar. */
.toolbar-filter-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: 0.4rem;
    margin: 0;
}
.toolbar-filter-dd { position: relative; }
.toolbar-filter-trigger {
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    background: transparent;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    color: var(--muted);
    padding: 0.25rem 0.6rem;
    font-size: 0.85rem;
    line-height: 1.3;
    font-family: inherit;
}
.toolbar-filter-trigger > i { font-size: 0.85rem; }
.toolbar-filter-trigger:hover { border-color: var(--accent); color: var(--fg); }
.toolbar-filter-trigger.has-selection {
    border-color: var(--accent);
    color: var(--accent);
    background: var(--icon-blue-soft);
}
.toolbar-filter-trigger.has-selection:hover { color: var(--accent); }
.toolbar-filter-trigger strong { font-weight: 600; color: var(--fg); }
.toolbar-filter-trigger.has-selection strong { color: var(--accent); }
.toolbar-filter-trigger-label { color: var(--muted); }
.toolbar-filter-caret {
    margin-left: 0.15rem;
    font-size: 0.7rem;
    transition: transform 120ms ease;
}
.toolbar-filter-dd.is-open .toolbar-filter-caret { transform: rotate(180deg); }

.toolbar-filter-menu {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    z-index: 50;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);
    min-width: 220px;
    max-height: 360px;
    overflow-y: auto;
    padding: 0.25rem 0;
}
.toolbar-filter-menu-list {
    list-style: none;
    margin: 0;
    padding: 0;
}
.toolbar-filter-menu-list li label {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.4rem 0.75rem;
    font-size: 0.88rem;
    color: var(--fg);
    cursor: pointer;
}
.toolbar-filter-menu-list li label:hover { background: var(--shade-2); }
.toolbar-filter-menu-list li label input { margin: 0; }
.toolbar-filter-menu-actions {
    display: flex;
    justify-content: flex-end;
    padding: 0.4rem 0.5rem 0.3rem;
    border-top: 1px solid var(--border);
    margin-top: 0.25rem;
}
.toolbar-filter-clear {
    cursor: pointer;
    background: transparent;
    border: 0;
    color: var(--muted);
    padding: 0.25rem 0.4rem;
    font-size: 0.8rem;
    font-family: inherit;
    text-decoration: underline;
    text-underline-offset: 2px;
    margin-left: 0.25rem;
}
.toolbar-filter-clear:hover { color: var(--accent); }

/* ============================================================
   Ticket quickview drawer (views/ticket-quickview.js)
   ------------------------------------------------------------
   Drawer for simple ticket handling: read the ticket, contact the user,
   reply/solve without leaving the current page. Layout from top:
   header → user-block → description → comments → form.
   ============================================================ */
.quickview { display: flex; flex-direction: column; gap: 1.25rem; }

/* Header — title on row 1, status pill below (align-self start so the
   pill isn't stretched to full width). Ticket id sits in drawer-head. */
.quickview-head { display: flex; flex-direction: column; gap: 0.5rem; }
.quickview-title {
    margin: 0;
    font-size: 1.15rem;
    line-height: 1.3;
    font-weight: 600;
}
.quickview-head .status-pill { align-self: flex-start; }

/* User block — the clickable button-card opens the profile drawer;
   contact icons on the right stop propagation so they don't also fire
   the profile drawer. */
.quickview-user {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.6rem 0.75rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--shade-1);
}
.quickview-user-button {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    flex: 1;
    min-width: 0;
    padding: 0;
    background: transparent;
    border: 0;
    border-bottom: 0;             /* override .user-link dashed underline */
    cursor: pointer;
    text-align: left;
    color: inherit;
}
.quickview-user-button:hover { color: var(--accent); }
.quickview-user-button:hover .quickview-user-text strong { color: var(--accent); }
.quickview-user-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
}
.quickview-user-text strong {
    font-size: 0.95rem;
    color: var(--fg);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    transition: color 0.12s;
}
.quickview-user-text .muted {
    font-size: 0.8rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.quickview-user-actions { display: inline-flex; gap: 0.25rem; }
.quickview-user-actions a {
    width: 32px;
    height: 32px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius);
    color: var(--muted);
    text-decoration: none;
    transition: background 0.12s, color 0.12s;
}
.quickview-user-actions a:hover {
    background: var(--surface);
    color: var(--accent);
}

/* Description — clamp if long; toggle button shows full text. */
.quickview-description h3,
.quickview-comments h3,
.quickview-form h3 {
    margin: 0 0 0.5rem;
    font-size: 0.78rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--muted);
}
.quickview-description-body {
    max-height: 8.5em;
    overflow: hidden;
    position: relative;
}
.quickview-description-body.is-expanded { max-height: none; }
.quickview-description-body:not(.is-expanded)::after {
    content: '';
    position: absolute;
    bottom: 0; left: 0; right: 0;
    height: 2.5em;
    background: linear-gradient(transparent, var(--surface));
    pointer-events: none;
}
.quickview-description-toggle { margin-top: 0.25rem; }

/* Comments — compact list, each row has an avatar + body. */
.quickview-comment-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.85rem;
}
.quickview-comment {
    display: flex;
    gap: 0.55rem;
    align-items: flex-start;
}
.quickview-comment-body {
    flex: 1;
    min-width: 0;
    padding: 0.5rem 0.75rem;
    background: var(--shade-1);
    border-radius: var(--radius);
}
.quickview-comment.is-private .quickview-comment-body {
    background: var(--icon-red-soft);
}
.quickview-comment.is-solution .quickview-comment-body {
    background: var(--icon-green-soft);
}
.quickview-comment-head {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    flex-wrap: wrap;
    margin-bottom: 0.25rem;
    font-size: 0.85rem;
}
.quickview-comment-head time { font-size: 0.75rem; }
.quickview-comment-body .prose {
    font-size: 0.9rem;
    line-height: 1.45;
    word-break: break-word;
}
.quickview-comment-body .prose p:first-child { margin-top: 0; }
.quickview-comment-body .prose p:last-child { margin-bottom: 0; }

/* Form — comment-editor wrapper with a frame, footer with split-button. */
.quickview-form-editor {
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    overflow: hidden;
}
.quickview-form-editor:focus-within {
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--icon-blue-soft);
}
.quickview-form-editor .comment-editor { min-height: 90px; }
.quickview-form-actions {
    display: flex;
    justify-content: flex-end;
    margin-top: 0.6rem;
}

/* ============================================================
   Merch register — full-page editor (views/agent-merc-item-edit.js)
   ------------------------------------------------------------
   Replaces the previous edit-modal in agent-merc-items.js. Two-column
   layout: text/details on the left, images/categories/visibility right.
   ============================================================ */
.merc-edit-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    margin: 0.5rem 0 1rem;
}
.merc-edit-head h1 {
    margin: 0;
    font-size: 1.5rem;
    color: var(--fg);
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.merc-edit-actions {
    display: inline-flex;
    gap: 0.5rem;
    flex-shrink: 0;
}

/* Banner shown when the item is soft-deleted — gives one clear action
   path (Gjenopprett) without hiding the rest of the page. */
.merc-edit-deleted-banner {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.75rem 1rem;
    background: var(--icon-red-soft);
    border: 1px solid var(--icon-red);
    border-radius: var(--radius);
    color: var(--icon-red);
    margin-bottom: 1rem;
    flex-wrap: wrap;
}
.merc-edit-deleted-banner i { font-size: 1.1rem; }
.merc-edit-deleted-banner .btn { margin-left: auto; }

/* Form grid: main content on the left, sidebar on the right (320px).
   Wraps on narrow screens — the sidebar drops below. */
.merc-edit-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 320px;
    gap: 1.5rem;
    align-items: start;
}
@media (max-width: 900px) {
    .merc-edit-grid { grid-template-columns: 1fr; }
}
.merc-edit-main,
.merc-edit-side {
    display: flex;
    flex-direction: column;
    gap: 1rem;
    min-width: 0;
}
.merc-edit-grid .admin-form-feedback { grid-column: 1 / -1; }
/* Danger-zone spans both columns at the bottom of merc-edit-grid —
   see design.md §Forms for the pattern. */
.merc-edit-grid .danger-zone { grid-column: 1 / -1; }

/* Footer buttons (Avbryt/Lagre) mirror the header buttons at the top — long
   forms should have "Lagre" within close reach of where the user
   finishes reading, not only at the top. Placed bottom-right where "Lagre"
   is conventionally expected; left-aligned "Slett vare" in the danger zone
   above removes the risk of mis-clicks. */
.merc-edit-grid .merc-edit-footer {
    grid-column: 1 / -1;
    display: flex;
    justify-content: flex-end;
    gap: 0.6rem;
    padding-top: 0.5rem;
}

/* Rich-text editor wrapper inside the form field — gives the editor a
   visible border and matching focus ring so it doesn't bleed out as a
   "blank box". */
.merc-edit-main [data-desc-editor] {
    border: 1px solid var(--border);
    border-radius: var(--radius);
    overflow: hidden;
    background: var(--surface);
}
.merc-edit-main [data-desc-editor]:focus-within {
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--icon-blue-soft);
}
.merc-edit-main .comment-editor { min-height: 200px; }

/* Orders page-head right group — filter pills + search-toggle on the
   same row, vertically aligned with the H1. Search-toggle sits last so
   it's a secondary affordance after the primary filter pills. */
.page-head-actions {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    flex-wrap: wrap;
}
.orders-search-toggle { margin-left: 0; }

/* Search input row — full width above the table when revealed.
   Hidden by default; the toggle button in page-head shows/hides it. */
.orders-search {
    display: flex;
    width: 100%;
    max-width: none;
    margin: 0 0 1rem;
}

/* ============================================================
   Orders pipeline overview — status tiles + tips panel
   (views/agent-merc-orders.js)
   ============================================================ */
.merc-orders-overview {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1.25rem;
    margin: 0 0 1.5rem;
}
@media (min-width: 960px) {
    .merc-orders-overview {
        grid-template-columns: minmax(0, 1fr) 280px;
        align-items: start;
    }
}

/* Pipeline tile row — one tile per in-flight status. Click filters the
   table; clicking the active tile clears the filter. Surface tokens come
   from the .surface utility (see design.md §Surface tokens). */
.merc-orders-pipeline {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
    gap: 0.6rem;
}
.pipeline-tile {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    padding: 0.9rem 0.5rem;
    text-align: center;
    cursor: pointer;
    color: var(--fg);
    font: inherit;
}
.pipeline-tile.is-active {
    border-color: var(--accent);
    background: var(--icon-blue-soft);
}
.pipeline-tile-icon {
    font-size: 1.8rem;
    color: var(--muted);
    line-height: 1;
}
.pipeline-tile.is-active .pipeline-tile-icon { color: var(--accent); }
.pipeline-tile-title {
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--muted);
}
.pipeline-tile.is-active .pipeline-tile-title { color: var(--fg); }
.pipeline-tile-badge {
    position: absolute;
    top: -6px;
    right: -6px;
    min-width: 22px;
    height: 22px;
    padding: 0 6px;
    border-radius: 11px;
    background: var(--icon-red);
    color: #fff;
    font-size: 0.78rem;
    font-weight: 600;
    line-height: 22px;
    text-align: center;
    box-shadow: 0 0 0 2px var(--bg);
}
.pipeline-tile-badge.is-zero {
    background: var(--shade-2);
    color: var(--muted);
}

/* Tips panel — info box with hint text matching old app's right-hand
   column on /agent/merc/orders. */
.merc-orders-tips {
    padding: 1rem 1.1rem;
    background: var(--shade-1);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    color: var(--muted);
    font-size: 0.82rem;
    line-height: 1.45;
}
.merc-orders-tips h3 {
    margin: 0 0 0.5rem;
    font-size: 0.9rem;
    font-weight: 600;
    color: var(--fg);
    display: flex;
    align-items: center;
    gap: 0.4rem;
}
.merc-orders-tips h3 i { color: var(--accent); }
.merc-orders-tips p {
    margin: 0 0 0.5rem;
}
.merc-orders-tips p:last-child { margin-bottom: 0; }

/* ------ .merc-order-row (structural — only grid/layout) ------
   Used by: /agent/merc/orders. Card pattern derived from .pending-row
   (avatar left, body middle, actions bottom-right) — fits
   the order's many fields without forcing a flat table row. Surface
   design (background/border/shadow/radius) comes from the shared
   .surface-utility — do NOT duplicate tokens here. */
.merc-order-row {
    display: grid;
    grid-template-columns: auto 1fr;
    grid-template-areas:
        "avatar body"
        ".      actions";
    column-gap: 1rem;
    row-gap: 0.6rem;
    align-items: start;
    padding: 1rem 1.25rem;
}
.merc-order-row-avatar { grid-area: avatar; }
.merc-order-row-body   { grid-area: body; min-width: 0; }
.merc-order-row-actions {
    grid-area: actions;
    justify-self: end;
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
}

/* Body — three stacked rows: head (title + ticket# + status pill),
   user line, financial line. */
.merc-order-row-head {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem 0.75rem;
    margin-bottom: 0.4rem;
}
.merc-order-row-title {
    font-size: 1rem;
    font-weight: 600;
    line-height: 1.35;
    color: var(--fg);
    flex: 1 1 auto;
    min-width: 0;
}
.merc-order-row-product {
    /* Product is a button styled as a link — overrides .link-button
       defaults so it inherits the title's bold + size. */
    font-size: inherit;
    font-weight: inherit;
    text-align: left;
    padding: 0;
}
.merc-order-row-ticket {
    color: var(--accent);
    font-size: 0.85rem;
    font-weight: 500;
    text-decoration: none;
    flex-shrink: 0;
}
.merc-order-row-ticket:hover { text-decoration: underline; }
.merc-order-row-head .status-pill { flex-shrink: 0; }

.merc-order-row-users {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem 0.75rem;
    margin-bottom: 0.4rem;
    font-size: 0.85rem;
}
.merc-order-row-users .user-inline { color: var(--fg); }

.merc-order-row-financial {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem 0.6rem;
    font-size: 0.85rem;
}
.merc-order-row-financial strong { color: var(--fg); }

/* Empty-state row inside .list — no card, just a muted message. */
.merc-order-empty {
    list-style: none;
    padding: 1.5rem;
    text-align: center;
}

/* Mobile: actions stretch full width like .pending-row. */
@media (max-width: 720px) {
    .merc-order-row {
        grid-template-areas:
            "avatar body"
            "actions actions";
    }
    .merc-order-row-actions {
        justify-self: stretch;
    }
    .merc-order-row-actions .btn { flex: 1; }
}

/* ============================================================
   Notifications settings — tab nav + outbox + template preview
   (views/agent-settings-notifications.js)
   ============================================================ */
.tab-nav {
    display: flex;
    gap: 0.25rem;
    margin: 0.75rem 0 1.25rem;
    border-bottom: 1px solid var(--border);
    flex-wrap: wrap;
}
.tab-nav-btn {
    background: transparent;
    border: 0;
    border-bottom: 2px solid transparent;
    color: var(--muted);
    padding: 0.6rem 0.95rem;
    cursor: pointer;
    font-family: inherit;
    font-size: 0.95rem;
    font-weight: 500;
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    margin-bottom: -1px;
    transition: color 0.12s, border-color 0.12s;
}
.tab-nav-btn:hover { color: var(--fg); }
.tab-nav-btn.is-active {
    color: var(--accent);
    border-bottom-color: var(--accent);
}
.tab-nav-btn i { font-size: 0.9rem; }

/* Outbox tab — toolbar at the top + list below. */
.outbox-toolbar {
    display: flex;
    align-items: end;
    gap: 0.75rem;
    margin: 0 0 1rem;
    flex-wrap: wrap;
}
.outbox-toolbar .admin-form-field { min-width: 180px; }
.outbox-toolbar .btn { align-self: end; margin-bottom: 1px; }

/* Notification detail modal — definition list of meta + iframe-rendered body. */
.notif-detail-meta {
    display: grid;
    grid-template-columns: 140px 1fr;
    gap: 0.4rem 1rem;
    margin: 0 0 1rem;
    font-size: 0.9rem;
}
.notif-detail-meta dt { color: var(--muted); font-weight: 500; }
.notif-detail-meta dd { margin: 0; word-break: break-word; }
.notif-detail-h {
    margin: 1rem 0 0.4rem;
    font-size: 0.85rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--muted);
}
.notif-detail-response {
    background: var(--shade-1);
    padding: 0.5rem 0.75rem;
    border-radius: var(--radius);
    font-size: 0.8rem;
    overflow-x: auto;
    margin: 0;
    white-space: pre-wrap;
    word-break: break-word;
}
.notif-detail-iframe {
    width: 100%;
    height: 320px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: white;
}

/* Notification template drawer — "Ny override" sits right after the
   override list/empty-state without a margin separator by default; add
   one so the button doesn't crowd the list above. */
.notif-section #btn-new-override { margin-top: 0.75rem; }

/* ------ /agent/settings/notifications#spam — admin spam blacklist ------
   Toolbar with search-on-left, add-button-on-right; the add-form lives
   below the toolbar and is hidden by default (toggled by the button) so
   it doesn't visually compete with the search input. */
.spam-toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 0.75rem;
    flex-wrap: wrap;
}
.spam-add-form { padding: 1rem 1.25rem; margin-bottom: 0.75rem; }
.spam-addr { display: inline-flex; align-items: center; gap: 0.5rem; }
.spam-addr-icon { color: var(--icon-red); }

/* ------ /agent/reports/without-service toolbar ------
   Sits between intro text and DataTable. "Triage tjeneste" button +
   count text on a single line. */
.without-service-toolbar {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin: 0.75rem 0 1rem;
    flex-wrap: wrap;
}

/* ------ Triage drawer ------
   Quick panel for "set one field on many tickets" — driven by
   views/triage-drawer.js. Default use: /agent/reports/without-service
   with field-config for the service field. Layout lives in drawer-body,
   so no panel-chrome here. */
.triage-progress {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    padding: 0.25rem 0 0.75rem;
    border-bottom: 1px solid var(--border);
    margin-bottom: 1rem;
}
.triage-progress-text { flex: 1; text-align: center; font-size: 0.9rem; }
.triage-ticket {
    background: var(--shade-1);
    border-radius: var(--radius);
    padding: 1rem;
    margin-bottom: 1.25rem;
    border: 1px solid var(--border);
}
.triage-ticket-num {
    font-size: 0.8rem;
    color: var(--muted);
    font-weight: 500;
    margin-bottom: 0.25rem;
}
.triage-ticket-title {
    margin: 0 0 0.5rem;
    font-size: 1rem;
    line-height: 1.35;
    word-break: break-word;
}
.triage-ticket-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    align-items: center;
    margin-bottom: 0.75rem;
    font-size: 0.85rem;
}
.triage-ticket-people {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    font-size: 0.85rem;
}
.triage-person { display: flex; gap: 0.4rem; align-items: baseline; }
.triage-person-label { min-width: 4.5rem; }
.triage-section-title {
    margin: 0 0 0.5rem;
    font-size: 0.85rem;
    font-weight: 500;
    color: var(--muted);
    text-transform: uppercase;
    letter-spacing: 0.03em;
}
.triage-recent { margin-bottom: 1.25rem; }
.triage-recent-chips { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.triage-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.35rem 0.6rem 0.35rem 0.4rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 999px;
    cursor: pointer;
    font-size: 0.85rem;
    line-height: 1;
    transition: border-color 0.15s, background 0.15s;
}
.triage-chip:hover { border-color: var(--accent); }
.triage-chip-key {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.4rem;
    height: 1.4rem;
    padding: 0 0.3rem;
    background: var(--shade-1);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.75rem;
    color: var(--muted);
}
.triage-chip:hover .triage-chip-key {
    border-color: var(--accent);
    color: var(--accent);
}
.triage-chip-label { font-weight: 500; }
.triage-search { margin-bottom: 1.25rem; }
.triage-actions {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
    padding-top: 0.75rem;
    border-top: 1px solid var(--border);
    margin-bottom: 0.75rem;
}
.triage-key {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.4rem;
    height: 1.4rem;
    padding: 0 0.3rem;
    background: var(--shade-1);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.75rem;
    color: var(--muted);
    margin-right: 0.25rem;
}
.triage-hint {
    font-size: 0.8rem;
    text-align: center;
    margin: 0;
    line-height: 1.8;
}
.triage-hint .triage-key { margin: 0 0.1rem; }
.triage-done {
    text-align: center;
    padding: 2rem 1rem;
}
.triage-done-icon {
    font-size: 3rem;
    color: var(--icon-green);
    display: block;
    margin-bottom: 1rem;
}
.triage-done h3 { margin: 0 0 0.5rem; }
.triage-done .btn { margin-top: 1rem; }

/* Lazy-loaded ticket details inne i triage-drawer */
.triage-details { margin-bottom: 1.25rem; }
.triage-details-loading {
    font-size: 0.85rem;
    padding: 0.5rem 0;
}
.triage-details-error {
    font-size: 0.85rem;
    padding: 0.5rem 0;
}
.triage-description { margin-bottom: 1rem; }
.triage-description-body {
    font-size: 0.9rem;
    line-height: 1.5;
    max-height: 7em;
    overflow: hidden;
    position: relative;
    /* Soft fade-out at the bottom so the agent sees there's more */
    mask-image: linear-gradient(to bottom, #000 70%, transparent 100%);
    -webkit-mask-image: linear-gradient(to bottom, #000 70%, transparent 100%);
}
.triage-description-body.is-expanded {
    max-height: none;
    mask-image: none;
    -webkit-mask-image: none;
}
.triage-description-toggle {
    margin-top: 0.25rem;
    font-size: 0.85rem;
}
.triage-no-body, .triage-no-comments {
    font-size: 0.85rem;
    margin: 0 0 1rem;
}
.triage-comments { margin-bottom: 1rem; }
.triage-comments-toggle {
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.5rem 0.75rem;
    background: var(--shade-1);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    cursor: pointer;
    font-size: 0.85rem;
    color: inherit;
    transition: border-color 0.15s;
}
.triage-comments-toggle:hover { border-color: var(--accent); }
.triage-comments-toggle[aria-expanded="true"] { border-bottom-left-radius: 0; border-bottom-right-radius: 0; }
.triage-comments-list {
    list-style: none;
    margin: 0;
    padding: 0;
    border: 1px solid var(--border);
    border-top: none;
    border-radius: 0 0 var(--radius) var(--radius);
    max-height: 22rem;
    overflow-y: auto;
}
.triage-comment {
    padding: 0.75rem;
    border-bottom: 1px solid var(--border);
    font-size: 0.85rem;
}
.triage-comment:last-child { border-bottom: none; }
.triage-comment.is-private { background: var(--shade-1); }
.triage-comment.is-system { background: var(--shade-1); font-style: italic; opacity: 0.85; }
.triage-comment-head {
    display: flex;
    gap: 0.5rem;
    align-items: baseline;
    flex-wrap: wrap;
    margin-bottom: 0.35rem;
    font-size: 0.8rem;
}
.triage-comment-head .badge {
    font-size: 0.7rem;
    padding: 0.05rem 0.4rem;
}
.triage-comment-body {
    font-size: 0.85rem;
    line-height: 1.5;
    word-break: break-word;
}
.triage-comment-body img { max-width: 100%; height: auto; }

/* "Allerede satt" badge above the picker — visible signal when the user
   navigates back to a ticket they've already handled. */
.triage-resolved-badge {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0.75rem;
    background: var(--icon-green-soft);
    border: 1px solid var(--icon-green);
    border-radius: var(--radius);
    margin-bottom: 1rem;
    font-size: 0.85rem;
}
.triage-resolved-badge i { color: var(--icon-green); }

/* Keyboard shortcuts help modal — listed via helpers/keyboard-shortcuts.js,
   opened via `?` or the user-menu entry. `/` is the visual separator when
   one action has multiple bindings (e.g. S / for search). */
.shortcuts-list {
    width: 100%;
    border-collapse: collapse;
}
.shortcuts-list td {
    padding: 0.5rem 0.25rem;
    border-bottom: 1px solid var(--border);
    vertical-align: middle;
}
.shortcuts-list tr:last-child td { border-bottom: none; }
.shortcuts-list .shortcuts-key {
    width: 1%;
    white-space: nowrap;
}
.shortcuts-list kbd {
    display: inline-block;
    min-width: 1.4rem;
    padding: 0.1rem 0.4rem;
    background: var(--shade-1);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.8rem;
    color: var(--fg);
    text-align: center;
    line-height: 1.4;
}
.shortcuts-hint {
    margin: 0.75rem 0 0;
    font-size: 0.85rem;
}
